JVM标志CMSClassUnloadingEnabled实际上是做什么的?
问题出现的原因是JAX-WS实现在每次web服务调用时都会创建一个新的代理类,最终导致内存溢出错误。通过设置JVM标志-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled
可以解决这个问题。添加这些标志后,临时类将从内存中删除。
解决方法是创建一个端口并重复使用它,这是使用JAX-WS的正确方式。这个端口也是100%线程安全的。在2012年时,每次调用上述逻辑都会创建一个新的代理。
此外,需要注意的是,-XX:+CMSPermGenSweepingEnabled
已经被-XX:+CMSClassUnloadingEnabled
取代,已经被弃用。
这个问题的一个实际解决方法是创建端口一次并重复使用它。这是JAX-WS的正确使用方式。端口也是100%线程安全的。
JVM flag CMSClassUnloadingEnabled是用来确定在CMS垃圾回收器下是否启用类卸载的。默认值是false。还有另一个选项叫做ClassUnloading,默认值是true,它(大概)影响其他垃圾回收器。
想法是,如果GC检测到之前加载的类在JVM中不再使用,它可以收回用于保存类字节码和/或本机代码的内存。
如果您当前正在使用CMS收集器,设置CMSClassUnloadingEnabled可能会有助于解决您的permgen问题。但是,您很可能没有使用CMS,或者存在真正的与类加载器相关的内存泄漏。在后一种情况下,您的类将永远不会被GC视为未使用...因此永远不会被卸载。
Aaron Digulla说“类是永恒的”。即使在纯Java世界中,这也不是严格正确的。实际上,类的生命周期与其类加载器相关联。因此,如果您可以安排一个类加载器被垃圾回收(这并不总是一件容易的事),它加载的类也将被垃圾回收。
实际上,当您进行热部署时,就会发生这种情况。(或者至少,如果您可以避免导致permgen存储泄漏的问题,应该是这样。)
JVM标志CMSClassUnloadingEnabled的作用是什么?
Java 5-7的情况:
标准的Oracle/Sun VM认为:类是永远的。一旦加载,即使没有人再使用,它们也会一直留在内存中。通常情况下,这不是一个问题,因为你没有那么多纯粹的“设置”类(即只用于设置一次,然后再也不使用)。所以即使它们占用了1MB的内存,谁在乎呢。
但最近,我们有了像Groovy这样的语言,它在运行时定义类。每次运行脚本时,都会创建一个(或多个)新的类,并且它们会永远留在PermGen中。如果你正在运行一个服务器,那意味着你有一个内存泄漏。
如果启用了CMSClassUnloadingEnabled,垃圾收集器也会清理PermGen,并删除不再使用的类。
[编辑]你还必须启用UseConcMarkSweepGC(感谢Sam Hasler)。请参考这个答案:https://stackoverflow.com/a/3720052/2541
根据stackoverflow.com/a/3720052/2541,要使CMSClassUnloadingEnabled发挥作用,还必须设置UseConcMarkSweepGC。
不确定这对于使用UseConcatSweepGC的想法有什么影响,但最近在CMSClassUnloadingEnabled中修复了一个错误。在这里被标记为已修复:bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325
对于像Groovy这样动态定义类的语言,启用此标志以定期清理PermGen是一个好的做法吗?
是的,绝对是。请参考groovy.codehaus.org/Running的底部:“Groovy动态创建类,但默认的Java虚拟机不会GC PermGen。如果您使用的是Java 6或更高版本,请添加-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC。需要UseConcMarkSweepGC来启用CMSClassUnloadingEnabled。”
如何解释这个bug报告?CMSClassUnloadingEnabled在哪个版本中设置为默认为true?我无法弄清楚。
关于如何同时使用UseConcMarkSweepGC和CMSClassUnloadingEnabled的一篇好文章。blog.redfin.com/devblog/2012/06/...
看起来我的假设是现在已经修复了。
对于1.8版本不再有效:blogs.oracle.com/poonam/...