CMS是一个"并发标记扫描",它是否会导致停顿事件?

14

我发现我的系统在卸载类时会出现很多挂起的情况...

[Unloading class sun.reflect.GeneratedMethodAccessor117]
[Unloading class sun.reflect.GeneratedConstructorAccessor1896]
[Unloading class sun.reflect.GeneratedSerializationConstructorAccessor485]
[Unloading class sun.reflect.GeneratedSerializationConstructorAccessor579]
.... // about 1700 of them

同时,我没有看到持久空间的峰值增加,因此它似乎不是GC事件。

我希望了解以下内容:

并发标记扫描收集是否是一种停顿全局事件?

即使持久空间没有满,它也会发生吗?


1
可以参考此JDK错误报告,它可能与你的问题有关。即使没有关闭stdout,这些消息的打印可能也是导致系统挂起的原因。请问您是否在使用旧版本的Java运行时环境? - Marko Topolnik
3个回答

22

内容经过翻译为:CMS是一种GC类型,分为多个阶段。

enter image description here

可以看到两个阶段 - 初始标记和重新标记是停顿事件。

来源:在审查分代GC和CMS部分中。

Does it happen even when the perm space is not full?

据我所知,为此您应该使用CMSClassUnloadingEnabledUseConcMarkSweepGC。当永久代区域达到其阈值时,将触发FGC。

尽管并发清除(第4个短语)不是STW事件,但如果永久代区域被填满(且GC仍在处理永久代区域),它可能会导致停止所有进程线程,并且只有GC线程运行,直至回收所有所需内存。


我可以假设卸载类sun.reflect -> 在短语(4)中吗? - user4127
1
这个字面上的复制粘贴并没有帮助回答楼主的具体问题。 - Marko Topolnik

5
CMS不是一个“事件”。它是一个垃圾回收器。CMS确实有几个阶段在这些阶段中,一切都停止了,但在正常情况下,这些阶段非常短暂(几毫秒)。通常,如果您遇到长时间的暂停,这意味着CMS无法跟上垃圾生成的速度(在设置的约束内),并且JVM必须使用“标记-清除”收集器执行完整的GC...这 停止世界。

根据您的JVM,可能是只有在进行完整的GC时才会收集permgen,并且当收集/卸载permgen时才会收集类。

但是你不能推断出类卸载导致长时间暂停。事实上,如果您的GC统计信息显示permgen没有填满,那么更有可能是反过来的。

还可能是您记录类卸载导致“停止世界”的问题:请参阅http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6637203


观察:

  • 如果您有成千上万条关于卸载动态创建的类的消息,那么我会查看系统的架构。您是否过度使用代理类?

  • 在Java 8中,permgen消失了,并被metaspace替换。升级可能会缓解您的问题。


1
通常Perm GC不会导致挂起问题。原因是在应用程序中的所有类加载完成后,Perm通常会稳定下来。如果JVM没有足够的内存,则可能会出现挂起问题。这意味着,在尝试进行Full-GC时,作为Full GC的一部分,将对Perm进行GC。
关于你提出的问题,CMS也会进行Full GC。它只是减少了Full GC的数量。在Minor GC期间,它还会收集旧的内存区域。
我认为,您可能在堆内存方面存在问题,这会导致大量的Full GC并导致挂起问题。因此,您需要使用Visual JVM工具或某些GC日志分析来检查内存使用情况。您可能会发现旧的内存区域已满,并且JVM尝试GC它。但是未释放足够的内存并重试gc。等等。
我认为您可能存在内存泄漏问题。因此最好进行GC日志分析,如果是内存泄漏问题,则需要进行堆转储并进行分析。

1
“Perm is usually stabilized after all classes...has been loaded”这句话对于一些应用程序可能是正确的,但显然不适用于OP的情况。 OP展示了运行时生成的短暂类的卸载,这些类是通过Reflection API中称为“膨胀”的优化生成的。这并不罕见,大多数应用程序都会动态生成字节码以实现某种目的。 - Marko Topolnik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接