为什么PermGen的空间越来越大?

我已经阅读了一些文章,我理解了以下内容(如果我错了,请纠正我和/或编辑问题):

java堆是这样分段的:

  • 年轻一代:创建的对象在这里,这部分经常和廉价的垃圾收集

  • 老一代:在Young年代的垃圾收集中存活的对象进入这里,这个区域垃圾收集频率较低,并且使用更多CPU要求的过程/算法(我相信它被称为标记扫描)

编辑:如其他用户所述,PermGen不是名为heap的区域的一部分

  • PermGen:这个区域充满了你的app类元数据和许多其他不依赖于应用程序使用的东西。

所以,知道这一点……为什么我的PermGen空间会在应用程序负载过重时增长? 对于我之前所说的这个空间不应该在应用程序加载的情况下逐渐填充,但正如我在开始时所说的那样,我可能错误地做了一些假设。

事实上,如果PermGen空间不断增长,有没有一种垃圾收集或重置的方法呢?

实际上,在Sun的JVM中,永久生成(PermGen)与堆完全分离。 你确定你没有看到Tenured Generation吗? 如果你的永久性一代继续增长,那将是可疑的。

如果你的权力不断增长,那么这是一个难以挖掘的领域。 通常,它应该在第一次加载新类时增长(并且可能某些reflection的使用也可能导致这种情况)。 Interned字符串也存储在perm gen中。

如果您碰巧在Solaris上,可以使用jmap -permstat来转储perm gen统计信息,但该选项似乎在Windows(以及可能的其他平台)上不可用。 这是关于jmap for Java 6的文档

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

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

  • Eden Space(堆):最初为大多数对象分配内存的池。
  • 幸存者空间(堆):包含在伊甸园空间的垃圾收集中幸存的对象的池。
  • Tenured Generation(堆):包含在幸存者空间中存在一段时间的对象的池。
  • 永久生成(非堆):包含虚拟机本身的所有reflection数据的池,例如类和方法对象。 对于使用类数据共享的Java VM,这一代分为只读区域和读写区域。
  • 代码缓存(非堆):HotSpot Java VM还包括代码缓存,其中包含用于编译和存储本机代码的内存。

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

  • 自定义类加载器,在加载新类之后不会小心地释放旧类。
  • 多次重新部署应用程序后,PermGen中剩余的类(在Dev中比Prod更常见)
  • 大量使用Proxy类,它们是在运行时合成创建的。 当单个类定义可以重用于多个实例时,很容易创建新的Proxy类。

这是调试中比较烦人的问题之一。 有很多原因你可以看到越来越多的使用permgen。 以下是我发现的2个链接,它们既可以了解泄漏的发生方式,也可以跟踪导致泄漏的原因。

http://frankkieviet.blogspot.com/2006/10/how-to-fix-dreaded-permgen-space.html

http://frankkieviet.blogspot.com/2006/10/classloader-leaks-dreaded-permgen-space.html

你在使用类加载器链做一些时髦的事吗? 你在一串字符串上调用intern()吗?

如果您正在使用Java EE应用程序,那么它可能是一个类加载器泄漏。

您可能会发现以下附加链接很有用:

http://www.zeroturnaround.com/blog/rjc201/

http://www.ibm.com/developerworks/java/library/j-dclp3/index.html

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

  1. 加载了Java类
  2. JAXBContext.newInstance
  3. 中的String.intern()

当您操作类加载器时,这是一个非常常见的问题。 当您重新部署hibernate / cglib时,Java EE应用程序中会出现很多这种情况。 欲了解更多信息,请查看

http://opensource.atlassian.com/confluence/spring/display/DISC/Memory+leak+-+classloader+won%27t+let+go