CMS后台线程
问题:你的意思是,在启动java程序的时候,jvm会调用其对应的c++代码,启动一个CMS后台线程来对这个java程序进行对象的垃圾回收?
解答:是的,你的理解完全正确!让我更详细地解释这个过程:
CMS垃圾收集器的工作机制
当你在启动Java程序时使用-XX:+UseConcMarkSweepGC参数,JVM会通过以下方式启动CMS垃圾收集器:
- JVM初始化阶段
- 在JVM启动时(通过
java命令),会调用底层的C++代码初始化垃圾收集器 - 如果指定了
-XX:+UseConcMarkSweepGC,JVM会选择CMS作为老年代(Old Generation)的垃圾收集器
- 在JVM启动时(通过
- CMS后台线程的创建
- JVM会启动一个名为"Concurrent Mark-Sweep GC Thread"的守护线程
- 这个线程在
concurrentMarkSweepThread.cpp中实现,核心类是ConcurrentMarkSweepThread - 它会在JVM整个生命周期中运行,负责并发标记和清理垃圾对象
- CMS的工作阶段
CMS的垃圾回收分为几个阶段,大部分工作是并发的(即与Java应用线程一起运行):- 初始标记(Initial Mark):短暂STW(Stop-The-World),标记GC Roots直接关联的对象
- 并发标记(Concurrent Marking):后台线程遍历对象图,标记存活对象
- 重新标记(Remark):短暂STW,修正并发标记期间变动的对象
- 并发清除(Concurrent Sweep):后台线程清理垃圾对象
如何验证CMS线程的存在?
你可以通过以下方式查看CMS后台线程:
1. 使用JVM参数打印GC日志
java -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -Xloggc:gc.log YourProgram
在日志中你会看到类似这样的输出:
[GC (CMS Initial Mark) [1 CMS-initial-mark: 18116K(136576K)] 29794K(196608K), 0.0003240 secs]
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.023/0.023 secs]
2. 使用jstack查看线程
jstack <your-java-pid>
在输出中查找:
"Concurrent Mark-Sweep GC Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f0b64010800 nid=0x7f1 runnable
3. 使用JVisualVM或JConsole
在"线程"标签页中,你会看到CMS的后台线程。
关键代码位置(OpenJDK 8)
如果你想深入研究CMS的实现,可以查看以下C++代码文件:
- CMS线程启动
hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cppConcurrentMarkSweepThread::start():启动CMS线程ConcurrentMarkSweepThread::run():线程主循环
- CMS核心逻辑
hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp- 实现了CMS的各个阶段(标记、清除等)
- 与Java的交互
System.gc()的调用最终会通过JNI到达:
hotspot/src/share/vm/prims/jvm.cpp中的JVM_GC()函数
重要注意事项
- CMS已被废弃
- 从JDK 9开始,CMS被标记为
deprecated - 在JDK 14中完全移除
- 现代Java应用建议使用G1或ZGC
- 从JDK 9开始,CMS被标记为
- CMS的缺点
- 内存碎片问题(可能导致
Concurrent Mode Failure) - 对CPU资源敏感(并发阶段占用CPU)
- 内存碎片问题(可能导致
- 替代方案
-XX:+UseG1GC(G1垃圾收集器,JDK 9+默认)-XX:+UseZGC(低延迟GC,JDK 11+)
总结
你的理解完全正确:当使用-XX:+UseConcMarkSweepGC时,JVM会在启动时通过C++代码初始化CMS垃圾收集器,并创建一个专用的后台线程来并发执行大部分垃圾回收工作,尽量减少对Java应用线程的影响。
浙公网安备 33010602011771号