推荐一个神器教你看懂GC日志
1、在idea中配置VM参数
-verbose:gc # 在控制台输出GC情况
-XX:+UseSerialGC # 使用Serial垃圾回收器
-Xms20M # 最小堆 20M
-Xmx20M # 最大堆 20M
-Xmn10M # 年轻代 10M
-XX:+PrintGCDetails # 打印GC日志细节
-XX:SurvivorRatio=8 # eden:survivor比值=8:1
VM虚拟机参数说明:
分配最小堆 20M,最大堆 20M,年轻代 10M,eden:survivor比值=8:1,所以eden区域 8M,from区域 1M,to区域 1M;老年代 10M。
2、编写测试代码
/**
* VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
*
* 10M新生代,eden:survivor 比例 8:1,所以eden 8192K,from:1024K,to:1024K
* 分配完allocation1,allocation2,allocation3之后,剩余空间不够分配allocation4,会发生MinorGC:PSYoungGen: 7052K->873K(9216K)]
* 新生代从7052K-》873K,
*
* 老年代10M,使用4MB,allocation4 分配到老年代(大对象或者是分配担保机制)
*
* @Date: 2021/3/31 21:09
*/
public class TestMinorGC {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[2 * _1MB];
allocation2 = new byte[2 * _1MB];
allocation3 = new byte[2 * _1MB];
allocation4 = new byte[4 * _1MB];
}
}
测试代码分配 4 个对象,allocation1、allocation2、allocation3空间2M,allocation4 空间4M。
这样的话,eden区域只有 8M,分配完allocation1、allocation2、allocation3,再分配allocation4空间就不够了,会触发MinorGC。
3、执行main方法输出
[GC (Allocation Failure) [PSYoungGen: 7054K->882K(9216K)] 7054K->4986K(19456K), 0.0036974 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
PSYoungGen total 9216K, used 7265K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
eden space 8192K, 77% used [0x00000007bf600000,0x00000007bfc3b958,0x00000007bfe00000)
from space 1024K, 86% used [0x00000007bfe00000,0x00000007bfedcb20,0x00000007bff00000)
to space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
ParOldGen total 10240K, used 4104K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
object space 10240K, 40% used [0x00000007bec00000,0x00000007bf002020,0x00000007bf600000)
Metaspace used 3217K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 355K, capacity 388K, committed 512K, reserved 1048576K
理解GC日志:
1、GC (Allocation Failure) 标示发生了 GC,如果出现 “FuLL GC“ 则表示这次GC发生了STW(stop the word),这里是GC,表示没有STW。
2、PSYoungGen:表示GC发生的区域为新生代,不同的垃圾回收器,这里的名称不一样,这里是 PSYoungGen 表示垃圾回收器是 Parallel Scavenge 收集器。
3、7054K->882K(9216K):表示新生代,“该区域GC发生前已使用容量->该区域GC发生后使用容量(该内容区域总容量)”。发生MinorGC,新生代空间从7054K到了882K。说明把allocation1、allocation2、allocation3都回收掉了。
4、7054K->4986K(19456K):表示Java堆总容量,“java堆GC发生前已使用容量->java堆GC发生后已使用容量(java堆总容量);说明回收之前,堆中存在allocation1、allocation2、allocation3三个对象,回收之后只有allocation4对象。
在MinorGC之前,堆中总共有三个对象allocation1、allocation2、allocation3,占用空间6.88M
在MinorGC之后,堆中共有1个对象,allocation4,占用4.88M
5、[Times: user=0.00 sys=0.00, real=0.00 secs] 用户态消耗CPU时间;内核态消耗CPU时间;操作从开始到结束的墙钟时间(包括非运算的等待耗时)。
5、新生代介绍
> PSYoungGen total 9216K, used 7265K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
> eden space 8192K, 77% used [0x00000007bf600000,0x00000007bfc3b958,0x00000007bfe00000)
> from space 1024K, 86% used [0x00000007bfe00000,0x00000007bfedcb20,0x00000007bff00000)
> to space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
表示新生代分为 eden区域、from区域,to区域,以及每个空间的大小,这里分别是 8M,1M,1M。
allocation1、allocation2、allocation3 各 2M,总共6M,存储在新生代eden区域,eden区域总共 8M,占比75%左右(垃圾回收之前)。
6、老年代介绍
表示老年代大小,和已使用的比例和容量
发生了MinorGC,但是发现allocation1、allocation2、allocation3不能都放入survivor区域,且没有被引用,都被回收掉了,所以allocation4,只能通过分配担保机制分配到老年代中,所以老年代占用4M,占比40%。
ParOldGen total 10240K, used 4104K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
object space 10240K, 40% used [0x00000007bec00000,0x00000007bf002020,0x00000007bf600000)
7、元空间
表示元空间大小,和已使用的比例和容量
Metaspace used 3217K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 355K, capacity 388K, committed 512K, reserved 1048576K
GC日志分析工具:https://blog.csdn.net/Prepared/article/details/115368331
代码地址:https://github.com/prepared48/Java-learning.git