单位是 byte,CompressedClassSpaceSize 的值是 1048576K(其实就是1G,默认值),InitialBootClassLoaderMetaspaceSize的值是 4M,用上面的公式计算,正好是 1056768K(1032M)
耗时统计
[Times: user=0.02 sys=0.00, real=0.01 secs]
user=0.02 表示执行用户态代码的耗时,这里也就是 GC 线程消耗的 CPU 时间。如果是多线程收集器,这个值会高于 real 时间。
sys=0.00 表示执行内核态代码的耗时。
real=0.01 表示应用停顿时长,多线程垃圾收集情况下,此数值应该接近(user + sys) / GCThreads(收集线程数),即单核上的平均停顿时间。
CMS 收集器
CMS 是一款老年代垃圾收集器,年轻代使用 ParNew 与之配合使用。它是一款并发、低停顿的垃圾收集器。适用于要求低延迟、即时响应的应用系统。
CMS 规划的内存模型和上面 Parallel Scavenge 的是一致的,可以参考上面的内存分布图。
CMS 采用标记-清除算法,算法过程比较复杂,分为一下几个步骤:
-
初始标记(CMS initial mark),会导致 stop the world;
-
并发标记(CMS concurrent mark),与用户线程同时运行;
-
预清理(CMS-concurrent-preclean),与用户线程同时运行;
-
可被终止的预清理(CMS-concurrent-abortable-preclean) 与用户线程同时运行;
-
重新标记(CMS remark),会导致 stop the world;
-
并发清除(CMS concurrent sweep),与用户线程同时运行;
-
并发重置状态等待下次CMS的触发(CMS-concurrent-reset),与用户线程同时运行;
只有初始标记和重新标记这两个步骤会导致 STW,但是这两个步骤耗时很短,其他步骤可以与用户线程同时运行,所以用户几乎感觉不到 JVM 停顿。
使用参数 -XX:+UseConcMarkSweepGC
可启用 CMS 垃圾收集器。更详细的参数如下:
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
-XX:+CMSClassUnloadingEnabled
-XX:+ParallelRefProcEnabled
在重新标记之前对年轻代做一次minor GC
-XX:+CMSScavengeBeforeRemark
使用了-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
或-XX:+ExplicitGCInvokesConcurrent
参数,在进行 Full GC 的时候,比如执行 System.gc() 操作,会触发 CMS GC,以此来提高 GC 效率。
以下是启用 CMS 后摘的一段 GC 日志,由于内容过长,下面我就直接在日志上做注释了。
System.gc() 触发一次 Full GC
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses 参数
导致Full GC 以 CMS GC 方式执行
先由 ParNew 收集器回收年轻代
2019-12-03T16:43:03.179-0800: [GC (System.gc()) 2019-1