187

CMSClassUnloadingEnabled除了一些非常模糊的高级定义,例如“摆脱你的 PermGen 问题”(它没有,顺便说一句)之外,我一生都找不到 Java VM 标志实际作用的定义。

我查看了 Sun 的/Oracle 的网站,甚至选项列表也没有真正说明它的作用。

根据标志的名称,我猜测 CMS 垃圾收集器默认情况下不会卸载类,并且此标志将其打开 - 但我不能确定。

4

3 回答 3

224

更新此答案与 Java 5-7 相关,Java 8 已修复此问题:https : //blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace乌鲁

对于 Java 5-7:

标准的 Oracle/Sun VM 对世界的看法是:类是永恒的。所以一旦加载,即使没有人关心,它们也会留在内存中。这通常没有问题,因为您没有那么多纯粹的“设置”类(= 一次用于设置,然后不再使用)。因此,即使它们占用 1MB,谁在乎。

但最近,我们有了像 Groovy 这样的语言,它们在运行时定义类。每次运行脚本时,都会创建一个(或多个)新类,并且它们会永远保留在 PermGen 中。如果您正在运行服务器,则意味着您有内存泄漏。

如果您启用CMSClassUnloadingEnabledGC,也会清除 PermGen,并删除不再使用的类。

[编辑]您还必须启用UseConcMarkSweepGC(感谢Sam Hasler)。看到这个答案:https ://stackoverflow.com/a/372​​0052/2541

于 2010-07-26T12:57:52.970 回答
36

根据博客文章The most complete list of -XX options for Java JVM,它确定是否在 CMS 垃圾收集器下启用类卸载。默认值为false. 默认情况下,还有另一个选项(ClassUnloading可能)会影响其他垃圾收集器。true

这个想法是,如果 GC 检测到先前加载的类不再在 JVM 中的任何地方使用,它可以回收用于保存类字节码和/或本机代码的内存。

如果您当前正在使用 CMS 收集器,设置 CMSClassUnloadingEnabled可能有助于解决您的 permgen 问题。但很有可能你没有使用 CMS,或者你有真正的类加载器相关的内存泄漏。在后一种情况下,您的类在 GC 看来永远不会被使用......因此永远不会被卸载。


Aaron Digulla 说“课程是永恒的​​”。严格来说,这并不正确,即使在纯 Java 世界中也是如此。事实上,一个类的生命周期与它的类加载器有关。因此,如果您可以安排对类加载器进行垃圾收集(这并不总是一件容易的事情),那么它加载的类也将被垃圾收集。

事实上,当您对 web 应用程序进行热重新部署时,就会发生这种情况。(或者至少,如果你能避免导致 permgen 存储泄漏的问题,那就应该发生这种情况。)

于 2010-07-26T13:00:18.683 回答
24

一个有用的例子:

在我们的 Weblogic 10.3 JVM 上进行设置-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled有助于解决 JAX-WS 实现为每个 Web 服务调用创建一个新的代理类,最终导致内存不足错误的问题。

追踪并非易事。以下代码始终返回相同的代理类port

final MyPortType port = 
Service.create(
        getClass().getResource("/path/to.wsdl"), 
        new QName("http://www.example.com", "MyService"))
    .getPort(
        new QName("http://www.example.com", "MyPortType"), 
        MyPortType.class);

在内部,此代理委托给 的实例weblogic.wsee.jaxws.spi.ClientInstance,该实例再次委托给一个新$Proxy[nnnn]类,该类n在每次调用时递增。添加标志时,n仍然递增,但至少那些临时类已从内存中删除。

更一般地说,这在大量使用 Java 反射和代理时非常有用java.lang.reflect.Proxy

于 2012-11-12T10:34:15.643 回答