JVM标志CMSClassUnloadingEnabled实际上是做什么的?

除了一些非常模糊的高级定义,例如“摆脱你的PermGen问题”( 它不是 ,顺便说一句),我不能为我的生活find什么Java VM标志CMSClassUnloadingEnabled实际上做的定义。

我已经看过Sun的/ Oracle的网站,甚至选项列表也没有说明它的作用。

根据国旗的名称,我猜CMS的垃圾收集器不会默认卸载类,这个标志打开它 – 但我不能确定。

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

对于Java 5-7:

标准的Oracle / Sun VM在世界上看起来是:类是永远的。 所以,一旦加载,即使没有人关心,他们仍然留在记忆中。 这通常是没有问题的,因为你没有那么多纯粹的“设置”类(=一次用于设置,然后不再)。 所以即使他们占用1MB,谁在乎。

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

如果启用CMSClassUnloadingEnabled则GC也将扫描PermGen,并删除不再使用的类。

[编辑]你也必须启用UseConcMarkSweepGC (感谢萨姆哈斯勒 )。 看到这个答案: https : //stackoverflow.com/a/372​​0052/2541

根据博客文章Java JVM的-XX选项的最完整列表 ,它确定在CMS垃圾收集器下是否启用类卸载。 默认值是false 。 还有另外一个叫做ClassUnloading选项,默认情况下是true ,这可能会影响到其他垃圾收集器。

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

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


亚伦Digulla说,“class是永远”。 即使在纯粹的Java世界中,这也不是完全正确的。 实际上,一个类的生命周期与它的类加载器有关。 所以如果你可以安排一个类加载器被垃圾收集(这并不总是一件容易的事情),它所加载的类也将被垃圾收集。

事实上,当你重新部署webapp的时候会发生这种情况。 (或者至less,如果你能避免导致泄漏存储泄露的问题,那将是什么情况呢?)

这是有用的一个例子:

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

追踪不是微不足道的。 下面的代码总是返回相同的代理类的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仍然增加,但至less这些临时类从内存中删除。

在更一般的说明中,当通过java.lang.reflect.Proxy大量使用Javareflection和代理时,这可能非常有用