JVM标志CMSClassUnloadingEnabled实际上做了什么?

除了一些非常模糊的高级定义,例如“摆脱PermGen问题”(它不会,顺便说一句),我无法在我的生活中找到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这样的语言,它们在运行时定义类。 每次运行脚本时,都会创建一个(或多个)新类,并永久保留在PermGen中。 如果您运行的是服务器,那意味着您有内存泄漏。

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

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


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

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

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


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

事实上,当你重新部署webapp时,会发生这种情况。 (或者至少,如果可以避免导致存储泄漏的问题,那么应该发生这种情况。)


这是有用的例子:

在我们的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.lang.reflect.Proxy大量使用Java反射和代理时,这可能非常有用

链接地址: http://www.djcxy.com/p/14457.html

上一篇: What does JVM flag CMSClassUnloadingEnabled actually do?

下一篇: Hidden Features of Java