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

问题描述 投票:0回答:3
我一生都找不到 Java VM 标志

CMSClassUnloadingEnabled

 实际作用的定义,除了一些非常模糊的高级定义,例如“摆脱你的 PermGen 问题”(
它没有) ,顺便说一句)。

我查看了 Sun/Oracle 的网站,甚至

选项列表实际上并没有说明它的作用。

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

java jvm classloader jvm-arguments
3个回答
226
投票

更新此答案与 Java 5-7 相关,Java 8 已修复此问题。 (感谢mt.uulu。)

对于 Java 5-7:

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

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

如果启用

CMSClassUnloadingEnabled

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

[编辑] 您还必须启用UseConcMarkSweepGC

(感谢
Sam Hasler)。请参阅此答案:https://stackoverflow.com/a/3720052/2541


36
投票
根据博文

Java JVM最完整的-XX选项列表,它决定了CMS垃圾收集器下是否启用类卸载。 默认为 false

。  还有另一个名为 
ClassUnloading
 的选项,默认情况下是 
true
,它(大概)会影响其他垃圾收集器。

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

设置 CMSClassUnloadingEnabled

可能有助于解决永久生成问题如果您当前正在使用 CMS 收集器。 但很可能您没有使用 CMS,或者您有真正的类加载器相关的内存泄漏。 在后一种情况下,您的类将永远不会出现在 GC 中未使用的...因此永远不会被卸载。


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

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


23
投票
此功能有用的示例:

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

© www.soinside.com 2019 - 2024. All rights reserved.