JVM 标记 CMSClassUnloadingEnable 实际上是做什么的?

除了一些非常模糊的高级定义,比如“摆脱 PermGen 问题”(但事实并非如此,btw) ,我一辈子都找不到 Java VM 标志 CMSClassUnloadingEnabled实际上做什么的定义。

我看过 Sun/Oracle 的网站,甚至 选择列表也没有说它到底是做什么的。

根据标志的名称,我猜测 CMS 垃圾收集器在默认情况下不会卸载类,而这个标志会打开它——但我不能确定。

105450 次浏览

更新 这个答案与 Java 5-7相关,Java 8已经修复了这个问题: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos 去到 < a href = “ https://stackoverflow. com/users/1076887/mt-uulu”> mt.uulu

Java 5-7:

Oracle/Sun VM 的标准外观是: 类是永恒的。所以一旦加载,他们留在内存中,即使没有人在乎了。这通常是没有问题的,因为您没有那么多纯粹的“安装”类(= 用于安装一次,然后再也不会)。所以即使它们占用1MB,谁在乎呢。

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

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

你还需要启用 UseConcMarkSweepGC(多亏了 Sam Hasler)参见这个答案: < a href = “ https://stackoverflow. com/a/3720052/2541”> https://stackoverflow.com/a/3720052/2541

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

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

设置 CMSClassUnloadingEnable也许吧有助于解决 permgen 问题 如果您当前正在使用 CMS 收集器。但是您可能没有使用 CMS,或者您有一个真正的类加载器相关的内存泄漏。在后一种情况下,您的类将永远不会显示为未使用... 因此将永远不会被卸载。


亚伦•迪古拉(Aaron 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 反射和代理时,这非常有用