25_模拟频繁 Full GC 案例
2770字约9分钟
2024-08-10
JVM 参数配置
下面这些参数基于 JDK1.8
版本来配置的,忘记怎么设置的可以回看 07_动手实验:系统部署时如何设置JVM内存大小 的内容
//初始新生代大小 最大新生代大小 初始堆内存大小 最大堆内存大小 Eden区占比新生代比例 大对象阈值 新生代垃圾器 ParNew 老年代垃圾器 CMS 打印详细 GC 日志 打印每次发生GC的时间 将GC 日志写入磁盘文件
-XX:NewSize=100M -XX:MaxNewSize=100M -XX:InitialHeapSize=200M -XX:MaxHeapSize=200M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=20M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log
我们这里设置堆内存 200MB
、新生代 100MB
、老年代 100MB
,大对象阈值为 20MB
代码
下面模拟的 Java
代码中,我们先停顿 20
秒,方便我们找到对应进程 PID
,然后执行 jstat
命令
每秒钟执行一次 loadData()
方法,分配 4
个 10MB
的数组,完了就成为垃圾对象
data1
、data2
两个 10MB
数组想是被变量引用的存活对象,此时 Eden
区已被占用六七十 MB
空间了
接着,data3
变量依次指向两个 10MB
数组,这是为了触发 Young GC
/**
* @ClassName AnalysisEngineDemo
* @Desciption
* @Author MaRui
* @Date 2024/2/2 18:26
* @Version 1.0
*/
public class AnalysisEngineDemo {
public static void main(String[] args) throws InterruptedException {
TimeUnit.SECONDS.sleep(20);
while (true) {
loadData();
}
}
private static void loadData() throws InterruptedException {
byte[] data = null;
for (int i = 0; i < 4; i++) {
data = new byte[10 * 1024 * 1024];
}
data = null;
byte[] data1 = new byte[10 * 1024 * 1024];
byte[] data2 = new byte[10 * 1024 * 1024];
byte[] data3 = new byte[10 * 1024 * 1024];
data3 = new byte[10 * 1024 * 1024];
TimeUnit.SECONDS.sleep(1);
}
}
结果分析
程序运行起来之后,我们可以看到,在第一秒就发生了一次 Young GC
,下面我们对日志一行一行进行分析
root@DESKTOP-GQ2O8E7 MINGW64 ~
$ jps
21696 AnalysisEngineDemo
7552 RemoteMavenServer36
11812
26836 RemoteMavenServer
11112
31516 Jps
33100 Launcher
root@DESKTOP-GQ2O8E7 MINGW64 ~
$ jstat -gc 21696 1000 1000
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
10240.0 10240.0 0.0 1479.0 81920.0 10240.0 102400.0 30722.1 4864.0 3832.9 512.0 424.2 1 0.014 0 0.000 0.014
10240.0 10240.0 1808.0 0.0 81920.0 23630.1 102400.0 51204.2 4864.0 3833.9 512.0 424.2 2 0.022 1 0.000 0.023
10240.0 10240.0 0.0 1866.6 81920.0 32251.9 102400.0 61444.2 4864.0 3834.0 512.0 424.2 3 0.027 1 0.000 0.027
10240.0 10240.0 1594.4 0.0 81920.0 42517.2 102400.0 30724.1 4864.0 3834.0 512.0 424.2 4 0.028 2 0.002 0.029
10240.0 10240.0 0.0 1908.6 81920.0 52773.5 102400.0 40964.2 4864.0 3834.0 512.0 424.2 5 0.029 2 0.002 0.031
10240.0 10240.0 1860.3 0.0 81920.0 63023.9 102400.0 51204.2 4864.0 3834.0 512.0 424.2 6 0.031 2 0.002 0.033
10240.0 10240.0 0.0 1991.3 81920.0 73270.6 102400.0 61444.2 4864.0 3834.0 512.0 424.2 7 0.033 3 0.002 0.035
10240.0 10240.0 0.0 1923.2 81920.0 10240.0 102400.0 40964.2 4864.0 3834.0 512.0 424.2 9 0.046 4 0.004 0.050
10240.0 10240.0 2008.8 0.0 81920.0 22079.4 102400.0 61444.2 4864.0 3834.0 512.0 424.2 10 0.049 5 0.004 0.053
10240.0 10240.0 0.0 1912.1 81920.0 32320.6 102400.0 71684.2 4864.0 3834.0 512.0 424.2 11 0.051 5 0.004 0.055
10240.0 10240.0 1805.1 0.0 81920.0 42561.3 102400.0 30724.1 4864.0 3834.0 512.0 424.2 12 0.052 6 0.005 0.057
10240.0 10240.0 0.0 1911.4 81920.0 52801.8 102400.0 40964.2 4864.0 3834.0 512.0 424.2 13 0.053 6 0.005 0.059
10240.0 10240.0 1860.9 0.0 81920.0 63042.1 102400.0 51204.2 4864.0 3834.0 512.0 424.2 14 0.055 6 0.005 0.060
10240.0 10240.0 0.0 1792.3 81920.0 73282.3 102400.0 61444.2 4864.0 3834.0 512.0 424.2 15 0.057 7 0.005 0.062
10240.0 10240.0 0.0 0.0 81920.0 10240.0 102400.0 42315.8 4864.0 3834.0 512.0 424.2 17 0.064 8 0.006 0.070
10240.0 10240.0 0.0 0.0 81920.0 22082.5 102400.0 62795.8 4864.0 3834.0 512.0 424.2 18 0.066 9 0.007 0.073
10240.0 10240.0 0.0 0.0 81920.0 32322.6 102400.0 73035.8 4864.0 3834.0 512.0 424.2 19 0.068 9 0.007 0.075
10240.0 10240.0 0.0 0.0 81920.0 42562.6 102400.0 32074.7 4864.0 3834.0 512.0 424.2 20 0.068 10 0.008 0.077
10240.0 10240.0 0.0 0.0 81920.0 52802.6 102400.0 42314.8 4864.0 3834.0 512.0 424.2 21 0.070 10 0.008 0.078
10240.0 10240.0 0.0 0.0 81920.0 63042.6 102400.0 52554.8 4864.0 3834.0 512.0 424.2 22 0.071 10 0.008 0.080
10240.0 10240.0 0.0 0.0 81920.0 73282.7 102400.0 62794.8 4864.0 3834.0 512.0 424.2 23 0.073 11 0.008 0.081
10240.0 10240.0 0.0 0.0 81920.0 10240.0 102400.0 42314.8 4864.0 3834.0 512.0 424.2 25 0.078 12 0.009 0.087
10240.0 10240.0 0.0 0.0 81920.0 22082.6 102400.0 62794.8 4864.0 3834.0 512.0 424.2 26 0.080 13 0.010 0.090
10240.0 10240.0 0.0 0.0 81920.0 32322.6 102400.0 73034.8 4864.0 3834.0 512.0 424.2 27 0.082 13 0.010 0.092
10240.0 10240.0 0.0 0.0 81920.0 42562.6 102400.0 32074.7 4864.0 3834.0 512.0 424.2 28 0.083 14 0.011 0.094
10240.0 10240.0 0.0 0.0 81920.0 52802.6 102400.0 42314.8 4864.0 3834.0 512.0 424.2 29 0.084 14 0.011 0.095
第一次执行 loadData()
方法时,Eden
区占用 0MB
,老年代占用 0MB
即将执行 data3 = new byte[10 * 1024 * 1024];
这行代码时,Eden
区已经被占用了 70MB
内存
Eden
区内存大小为 80MB
,显然无法继续放入一个 10MB
数组对象,这就是为什么我们程序运行起来第一秒就发生 Young GC
Survivor
内存大小为 10MB
,无法放入 Eden
区存活对象,所以 Eden
区 data1
、data2
、data3
变量引用的共 30MB
数组对象直接放入老年代,Eden
区回收掉 data
现在没引用的 40MB
数组对象,Eden
区放入 data3 = new byte[10 * 1024 * 1024];
创建的 10MB
数组
下面日志证明了我们的猜想,Young GC
之后 Eden
区占用 10MB
,老年代占用 30MB
EC EU OC OU YGC YGCT FGC FGCT GCT
81920.0 10240.0 102400.0 30722.1 1 0.014 0 0.000 0.014
第二次执行 loadData()
方法时,Eden
区占用 10MB
,老年代占用 30MB
即将执行 byte[] data3 = new byte[10 * 1024 * 1024];
时,Eden
区内存占用为 70MB
,无法放入一个 10MB
数组对象,发生 Young GC
这时,data1
、data2
变量引用的共 20MB
数组对象直接进入老年代,Eden
区回收掉 data
现在没引用的 40MB
数组对象,放入后续 data3
引用的共计 20MB
数组对象
下面日志也验证了我们的猜想,Young GC
之后 Eden
区占用 20MB
,老年代占用 50MB
EC EU OC OU YGC YGCT FGC FGCT GCT
81920.0 23630.1 102400.0 51204.2 2 0.022 1 0.000 0.023
第三次执行 loadData()
方法时,Eden
区占用 20MB
,老年代占用 30MB
即将执行 byte[] data2 = new byte[10 * 1024 * 1024];
时,Eden
区内存占用为 70MB
,无法放入一个 10MB
数组对象,发生 Young GC
这时,data1
变量引用的共 10MB
数组对象直接进入老年代,Eden
区回收掉 data
现在没引用的 40MB
数组对象,放入后续 data2
、data3
引用的共计 30MB
数组对象
下面日志也验证了我们的猜想,Young GC
之后 Eden
区占用 30MB
,老年代占用 60MB
EC EU OC OU YGC YGCT FGC FGCT GCT
81920.0 32251.9 102400.0 61444.2 3 0.027 1 0.000 0.027
第四次执行 loadData()
方法时,Eden
区占用 30MB
,老年代占用 60MB
即将执行 byte[] data1 = new byte[10 * 1024 * 1024];
时,Eden
区内存占用为 70MB
,无法放入一个 10MB
数组对象,发生 Young GC
这时,data
变量引用的共 10MB
数组对象直接进入老年代,Eden
区回收掉 data
现在没引用的 30MB
数组对象,放入后续 data1
、data2
、data3
引用的共计 40MB
数组对象
下面日志也验证了我们的猜想,Full GC
之后 Eden
区占用 40MB
但是老年代占用 30MB
,是不符合我们预期的 70MB
,老年代剩余 40MB
,历次 Young GC
进入老年代对象平均大小为 20MB
,老年代空间担保机制是够的,不会触发 Full GC
这个触发 Full GC
的搞不懂,只能猜测他 Full GC
后老年代只回收了 40MB
内存,还有需要注意的是,日志每一行不一定代表执行一次 loadData()
方法
EC EU OC OU YGC YGCT FGC FGCT GCT
81920.0 42517.2 102400.0 30724.1 4 0.028 2 0.002 0.029
看日志中的
GC
时间,29
次Young GC
耗时84
毫秒,平均一次接近3
毫秒,14
次Full GC
耗时11
毫秒,平均一次一毫秒不到,为什么Young GC
这么耗时呢?
按照上述代码,每次Full GC
都是由Young GC
触发的,得等Full GC
执行完毕后,Young GC
才能把存活对象放入老年代,这才算结束,这就导致Young GC
显示的耗时比较长
性能优化
之前 JVM
参数配置下,最大的问题是每次 Young GC
过后存活对象太多,频繁进入老年代,触发 Full GC
,我们调大年轻代以及增加 Survivor
内存空间即可
//初始新生代大小 最大新生代大小 初始堆内存大小 最大堆内存大小 Eden区占比新生代比例 大对象阈值 新生代垃圾器 ParNew 老年代垃圾器 CMS 打印详细 GC 日志 打印每次发生GC的时间 将GC 日志写入磁盘文件
-XX:NewSize=200M -XX:MaxNewSize=200M -XX:InitialHeapSize=300M -XX:MaxHeapSize=300M -XX:SurvivorRatio=2 -XX:PretenureSizeThreshold=20M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log
我们把堆大小调整为 300MB
,年轻代调整为 200MB
,同时 -XX:SurvivorRatio=2
表示,Eden : Survivor : Survivor
= 2 : 1 : 1
,也就是 Eden
区 100MB
,每个 Survivor
区 50MB
我们运行程序,用 jstat
监控运行状态如下,每次 Young GC
过后会有 10MB
左右存活对象进入 Survivor
,几乎没有对象进入老年代
每次 Young GC
耗时不过两三毫秒
$ jstat -gc 15180 1000 100
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
51200.0 51200.0 0.0 0.0 102400.0 92160.6 102400.0 0.0 4480.0 769.8 384.0 75.8 0 0.000 0 0.000 0.000
51200.0 51200.0 0.0 1546.8 102400.0 83877.1 102400.0 0.0 4864.0 3832.6 512.0 424.2 1 0.001 0 0.000 0.001
51200.0 51200.0 12041.5 0.0 102400.0 75630.1 102400.0 0.0 4864.0 3833.6 512.0 424.2 2 0.005 0 0.000 0.005
51200.0 51200.0 0.0 12250.4 102400.0 63363.7 102400.0 0.0 4864.0 3833.7 512.0 424.2 3 0.010 0 0.000 0.010
51200.0 51200.0 12096.6 0.0 102400.0 53152.6 102400.0 0.0 4864.0 3833.7 512.0 424.2 4 0.011 0 0.000 0.011
51200.0 51200.0 0.0 1868.5 102400.0 42931.1 102400.0 0.0 4864.0 3833.7 512.0 424.2 5 0.012 0 0.000 0.012
51200.0 51200.0 12319.4 0.0 102400.0 32703.0 102400.0 0.0 4864.0 3833.7 512.0 424.2 6 0.014 0 0.000 0.014
51200.0 51200.0 0.0 22560.3 102400.0 22470.7 102400.0 0.0 4864.0 3833.7 512.0 424.2 7 0.020 0 0.000 0.020
51200.0 51200.0 32592.5 0.0 102400.0 10240.0 102400.0 0.0 4864.0 3833.7 512.0 424.2 8 0.032 0 0.000 0.032
51200.0 51200.0 32592.5 0.0 102400.0 94155.7 102400.0 0.0 4864.0 3833.7 512.0 424.2 8 0.032 0 0.000 0.032
51200.0 51200.0 0.0 0.0 102400.0 83918.8 102400.0 1353.9 4864.0 3833.7 512.0 424.2 9 0.037 0 0.000 0.037
51200.0 51200.0 10240.0 0.0 102400.0 73680.9 102400.0 1353.9 4864.0 3833.7 512.0 424.2 10 0.039 0 0.000 0.039
51200.0 51200.0 0.0 10240.0 102400.0 63442.1 102400.0 1353.9 4864.0 3833.7 512.0 424.2 11 0.040 0 0.000 0.040
51200.0 51200.0 10240.0 0.0 102400.0 53203.0 102400.0 1353.9 4864.0 3833.7 512.0 424.2 12 0.042 0 0.000 0.042
51200.0 51200.0 0.0 0.0 102400.0 42963.5 102400.0 1353.9 4864.0 3833.7 512.0 424.2 13 0.042 0 0.000 0.042
51200.0 51200.0 10240.0 0.0 102400.0 32723.8 102400.0 1353.9 4864.0 3833.7 512.0 424.2 14 0.044 0 0.000 0.044
51200.0 51200.0 0.0 20480.0 102400.0 22484.0 102400.0 1353.9 4864.0 3833.7 512.0 424.2 15 0.046 0 0.000 0.046
51200.0 51200.0 30720.0 0.0 102400.0 10240.0 102400.0 1353.9 4864.0 3833.7 512.0 424.2 16 0.050 0 0.000 0.050
51200.0 51200.0 30720.0 0.0 102400.0 94164.3 102400.0 1353.9 4864.0 3833.7 512.0 424.2 16 0.050 0 0.000 0.050
51200.0 51200.0 0.0 0.0 102400.0 83924.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 17 0.051 0 0.000 0.051
51200.0 51200.0 10240.0 0.0 102400.0 73684.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 18 0.052 0 0.000 0.052
51200.0 51200.0 0.0 10240.0 102400.0 63444.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 19 0.054 0 0.000 0.054
51200.0 51200.0 10240.0 0.0 102400.0 53204.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 20 0.056 0 0.000 0.056
51200.0 51200.0 0.0 0.0 102400.0 42964.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 21 0.056 0 0.000 0.056
51200.0 51200.0 10240.0 0.0 102400.0 32724.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 22 0.057 0 0.000 0.057
51200.0 51200.0 0.0 20480.0 102400.0 22484.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 23 0.060 0 0.000 0.060
51200.0 51200.0 30720.0 0.0 102400.0 10240.0 102400.0 1353.9 4864.0 3833.7 512.0 424.2 24 0.064 0 0.000 0.064
51200.0 51200.0 30720.0 0.0 102400.0 94164.5 102400.0 1353.9 4864.0 3833.7 512.0 424.2 24 0.064 0 0.000 0.064
51200.0 51200.0 0.0 0.0 102400.0 83924.5 102400.0 1353.9 4864.0 3833.7 512.0 424.2 25 0.064 0 0.000 0.064
51200.0 51200.0 10240.0 0.0 102400.0 73684.5 102400.0 1353.9 4864.0 3833.7 512.0 424.2 26 0.066 0 0.000 0.066
51200.0 51200.0 0.0 10240.0 102400.0 63444.5 102400.0 1353.9 4864.0 3833.7 512.0 424.2 27 0.067 0 0.000 0.067
51200.0 51200.0 10240.0 0.0 102400.0 53204.5 102400.0 1353.9 4864.0 3833.7 512.0 424.2 28 0.069 0 0.000 0.069
51200.0 51200.0 0.0 0.0 102400.0 42964.5 102400.0 1353.9 4864.0 3833.7 512.0 424.2 29 0.069 0 0.000 0.069
51200.0 51200.0 10240.0 0.0 102400.0 32724.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 30 0.071 0 0.000 0.071
51200.0 51200.0 0.0 20480.0 102400.0 22484.4 102400.0 1353.9 4864.0 3833.7 512.0 424.2 31 0.074 0 0.000 0.074
51200.0 51200.0 30720.0 0.0 102400.0 10240.0 102400.0 1353.9 4864.0 3833.7 512.0 424.2 32 0.078 0 0.000 0.078