【问题标题】:What does JVM flag CMSClassUnloadingEnabled actually do?JVM 标志 CMSClassUnloadingEnabled 实际上是做什么的?
【发布时间】:2011-03-21 01:54:14
【问题描述】:

我一辈子都找不到Java VM标志CMSClassUnloadingEnabled实际作用的定义,除了一些非常模糊的高级定义,例如“摆脱你的PermGen问题”(which it doesn't,顺便说一句)。

我查看过 Sun/Oracle 的网站,甚至 the options list 并没有真正说明它的作用。

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

【问题讨论】:

    标签: java jvm classloader jvm-arguments


    【解决方案1】:

    更新此答案与 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/3720052/2541

    【讨论】:

    【解决方案2】:

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

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

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


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

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

    【讨论】:

      【解决方案3】:

      一个有用的例子:

      在我们的 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 反射和代理时非常有用

      【讨论】:

      • +1 分享真实体验。我们在 Torquebox 上也遇到了这个问题,由于 JRuby 编译过程,服务器生成了大量的类。
      • 另请注意,-XX:+CMSPermGenSweepingEnabled 已弃用,取而代之的是 -XX:+CMSClassUnloadingEnabled
      • 一个真正解决这个问题的方法是创建一次端口并重新使用它。这就是应该使用 JAX-WS 的方式。该端口也是 100% 线程安全的。
      • @rukavitsya:正如我在回答中所说的那样。每次调用上述逻辑,都会创建一个新的代理
      • @rukavitsya:嘿,对不起,我不知道。那是在 2012 年……我现在从事其他项目。
      猜你喜欢
      • 1970-01-01
      • 2011-03-11
      • 2010-11-26
      • 2015-06-23
      • 2017-12-26
      • 2016-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多