前言:
上一篇我们分析了 Minor GC 的发生过程,因为 GC 日志没有按我们预估的思路进行打印,其中打印了 CMS 垃圾回收器的部分日志,本篇我们就来分析一下 CMS 垃圾收集日志。
JVM 系列文章传送门
JVM 性能调优 – 线上应用 JVM 内存的的预估设置【实战】
JVM 性能调优 – 模拟触发 Minor GC【GC 日志分析】
JVM 性能调优 – 模拟触发 Minor GC(2)【GC 日志分析】
CMS 垃圾收集器出发的条件
我们知道 CMS 垃圾收集器是老年代的垃圾回收器,因此想要触发 CMS 垃圾回收,就必须触发老年代的 GC,也就是 Full GC,因此 CMS 垃圾收集器出发的条件就是 Full GC 的触发条件,如下:
- 老年代空间不足:Minor GC 后,有对象要晋升到老年代,此时老年代空间也不足,触发 Full GC。大对象直接在老年代创建的时候,发现老年代内存不足,直接触发 Full GC。
- 永久代空间不足:永久代默认空间是 21MB,如果永久代空间不足,也会触发 Full GC。
- 代码中显示调用 System.gc(),这种方式也会触发 Full GC,但是不会马上出发 Full GC。
可以知道简单的方式是调用 System.gc() 方法,不过本篇我们采用让老年代空间不足的方式来触发 Full GC。
JVM 配置
为了尽快触发 Full GC 我们调整年轻代老年代的空间占比,具体 JVM 参数如下:
-XX:NewSize=2m -XX:MaxNewSize=2m -Xms4m -Xmx4m -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:gc.log
上述 JVM 的参数在上一篇都逐个解释过,这里就不在逐个解释了,这里只简单陈述一下堆空间内存分配情况,新生代初始内存空间大小 2MB,新生代最大内存空间大小 2MB,初始堆内存大小 4MB,最大堆内存大小 4MB。
案例代码
案例代码我们还是使用上一篇中使用的案例代码,如下:
@Slf4j
public class MinorGcDemo {
public static void main(String[] args) {
byte[] array = new byte[1024 * 1024];
array = new byte[1024 * 1024];
array = new byte[1024 * 1024 * 2];
log.info("结束了");
}
}
我们创建了 2个 1MB 对象和 1个 2MB 对象,一共 4MB 的对象,整个堆内存我只分配了 4MB 的内存空间(内存占用情况的演进就不演示了),在加上对象的对象头等占用的内存,整个堆内存空间肯定是不足的,一定会发生 Full GC 并发生 OutOfMemoryError 错误,我们启动程序验证一下。
启动程序验证
启动程序后控制台如下:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.order.service.controller.MinorGcDemo.main(MinorGcDemo.java:17)
是按着我们的推理来打印的,控制台打印了 OutOfMemoryError 错误。