为什么PermGen空间会增长?

17

我阅读了几篇文章,理解如下(如果我有误,请纠正和/或编辑问题):

Java堆像这样划分:

  • 年轻代:创建的对象放在这里,这一部分通常使用廉价的垃圾回收进行回收

  • 老年代:在年轻代的垃圾回收中幸存下来的对象放在这里,这个区域的垃圾回收不那么频繁,并使用更耗费CPU的过程/算法(我相信它被称为“标记-扫描”)

编辑:正如另一个用户所述,PermGen不是称为heap的区域的一部分

  • PermGen:这个区域填充了你的应用程序类元数据和许多其他不依赖于应用程序使用情况的内容。

所以,知道了这些...为什么我的PermGen空间在应用程序负载较重时会增长呢?根据我之前所说,这个空间不应该随着应用程序负载的增加而逐渐填满,但是正如我在开头所说的,我可能对某些假设有误。

实际上,如果PermGen空间正在增长,是否有一种垃圾回收或重置它的方法?


你能进一步说明当你的永久代增长时发生了什么吗?你是如何观察到你的永久代正在增长的? - Joshua McKinnon
7个回答

19

实际上,在Sun的JVM中,永久生成区(PermGen)与堆完全独立。你确定你没有看错年老代(Tenured Generation)吗?如果你的永久生成区不断增长,这确实是令人怀疑的。

如果你的永久生成区确实不断增长,那么这是一个比较难解决的问题。通常情况下,当第一次加载新类时(以及潜在地使用反射的某些方式),永久生成区应该会增长。国际化字符串也存储在永久生成区。

如果你正在使用Solaris操作系统,可以使用jmap -permstat命令来转储永久生成区的统计信息,但这个选项似乎在Windows和其他平台上不可用。这里是Java 6的jmap文档

根据Sun的JConsole指南(它可以让你查看这些池的大小):

对于HotSpot Java VM,串行垃圾收集的内存池如下:

  • 伊甸园空间(堆):大多数对象最初分配内存的池。
  • 幸存者空间(堆):包含在伊甸园空间中进行垃圾回收后幸存下来的对象。
  • 年老代(堆):包含在幸存者空间中存在一段时间的对象。
  • 永久生成区(非堆):包含虚拟机本身的所有反射数据,如类和方法对象。对于使用类数据共享的Java VM,该代被划分为只读区域和可读写区域。
  • 代码缓存(非堆):HotSpot Java VM还包括一个代码缓存,包含用于编译和存储本机代码的内存。

6

我见过的最常见的原因包括:

  • 自定义类加载器在加载新类之后没有仔细释放旧类。
  • 在多次重新部署应用程序后,类仍然停留在PermGen中(在Dev中比在Prod中更常见)
  • 大量使用代理类,在运行时合成。当一个单一的类定义可以被多个实例重用时,很容易创建新的代理类。

6

+1 给这些超棒的链接。上周我偶然发现了其中一个,但后来却丢失了链接。 - Joshua McKinnon

2

你是否在对类加载器链进行奇怪的操作?你是否在一堆字符串上调用了intern()方法?


不,应用程序的“重头戏”在于反序列化一个大对象图,但该图主要是包含字符串的HashMap。也许这会调用“intern”函数? - Pablo Fernandez
2
不是的。HashMap 不调用 intern() 方法。 - Jonathan Feinberg

2

0

0

我见过的最常见的原因是:

  1. Java类被加载
  2. JAXBContext.newInstance
  3. String.intern()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接