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/3720052/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反射和代理时,这可能非常有用
上一篇: What does JVM flag CMSClassUnloadingEnabled actually do?