Java垃圾收集器如何清理PermGen?

4

垃圾收集器列表:

  • 串行垃圾收集器
  • 并行垃圾收集器
  • 并行老年代垃圾收集器
  • 并发标记清除垃圾收集器
  • G1垃圾收集器

我知道,如果启用ClassUnloading JVM选项,则Conc Mark Sweep垃圾收集器支持清理PermGen。其他垃圾收集器是否支持清理PermGen?

原因:我们使用Spring、Hibernate和Groovy创建了很多代理,导致Perm Gen变得很大。

编辑: 应该提到我正在使用Java 7。我知道Java 8移除了Perm Gen,希望将来升级。在此期间,我的问题是除了Conc Mark Sweep外,其他垃圾收集器是否支持清理PermGen。

  • 串行垃圾收集器
  • 并行垃圾收集器(相信-server默认使用此选项并确认它可以清理PermGen)
  • 并行老年代垃圾收集器
  • 并发标记清除垃圾收集器(可以使用JVM标志清理PermGen)
  • G1垃圾收集器

1
如果你遇到了OOME:PermGen空间错误,那么很可能是由于内存泄漏而不是故障的GC引擎。 - Marko Topolnik
1
你可以升级到Java 8,其中PermGen已被移除。 - Jesper
2个回答

5

所有的算法都会清理PermGen,但

  • 并不是每个GC循环都包括PermGen清理
  • CMS可以同时清理PermGen,G1直到Java 8u40仍需要暂停全GC来卸载类(清除PermGen)
  • Java 8有metaspace代替PermGen,但它也需要进行垃圾回收 (否则将在metaspace中出现OOME)

当我积极使用ClassLoaders模拟单个进程中的多个JVM以进行测试时,我一直在与PermGen中的OOM错误作斗争。我的结论是:PermGen GC并不是非常可靠。一个运行正常,另一个就会抛出OOM错误。


2
使用CMS(通过-XX:+UseConcMarkSweepGC启用)可能需要添加一些JVM参数来实际进行PermGen的垃圾回收。我认为最常见的是您需要添加-XX:+CMSClassUnloadingEnabled。有时您还需要-XX:+CMSPermGenSweepingEnabled,因此我建议在启动时添加并观察stdout / stderr。我也同意不可预测性,至少对于Parallell而言。 CMS和G1对我来说更加可靠,同时在我的ClassLoader Leak Prevention library上工作。 - Mattias Jiderhamn

-1
Perm Gen的问题在于它本来不应该是动态的,它应该是静态数据,比如类和常量。但我们开发人员使用Java时所做的事情包括动态创建类、重新定义类等,这需要更动态地使用该空间,这就是为什么在元空间的情况下必须这样做的原因。
最大的问题是Perm Gen,回到你的问题,我认为即使使用元空间也无法解决类加载器的创建和销毁问题,因为很容易在ThreadLocals和其他由其他类加载器加载的库中泄漏类元数据,这将留下无法被任何收集器回收的活对象。
现在,所有生产垃圾收集器都会清理元空间,但它们不一定以与其他内存区域相同的频率进行清理。

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