为什么PermGen空间越来越大?

时间:2010-01-12 19:30:35

标签: java memory-leaks memory-management

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

java堆是这样分段的:

  • Young Generation:创建的对象到这里,这部分经常被廉价地垃圾收集

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

编辑:如其他用户所述,PermGen不属于名为heap的区域

  • PermGen:此区域填充了您的应用类元数据以及许多其他不依赖于应用程序使用情况的内容。

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

事实上,如果PermGen空间在增长,是否有一种垃圾收集或重置方式?

7 个答案:

答案 0 :(得分:19)

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

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

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

来自Sun的guide on JConsole(可让您查看这些池的大小):

  

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

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

答案 1 :(得分:6)

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

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

答案 2 :(得分:6)

这是调试中比较烦人的问题之一。有很多原因你可以看到越来越多的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

答案 3 :(得分:2)

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

答案 4 :(得分:2)

如果您正在使用Java EE应用程序,则可能是类加载器泄漏。

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

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

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

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

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