读懂jvm内存回收日志
原创2022年3月5日大约 2 分钟
测试用例
public class Main {
//-Xmx20m -Xms20m -Xmn10m -XX:+PrintGCDetails
public static void main(String[] args) throws InterruptedException {
int num = 1024*1024;
//4*1024*1024个字节=4*1024KB=4MB
byte[] _4M = new byte[4*num];
byte[] _5M = new byte[5*num];
System.gc();
Thread.sleep(11133333);
}
}
日志
[GC (System.gc()) [PSYoungGen: 5783K->720K(9216K)] 10904K->9944K(19456K), 0.0036960 secs] [Times: user=0.00 sys=0.04, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 720K->0K(9216K)] [ParOldGen: 9224K->9577K(10240K)] 9944K->9577K(19456K), [Metaspace: 3275K->3275K(1056768K)], 0.0041171 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
[Full GC (Ergonomics) [PSYoungGen: 8192K->649K(9216K)] [ParOldGen: 9577K->10194K(10240K)] 17769K->10844K(19456K), [Metaspace: 8749K->8749K(1056768K)], 0.0086845 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
......省略
第一条GC日志
[GC (System.gc()) [PSYoungGen: 5783K->720K(9216K)] 10904K->9944K(19456K), 0.0036960 secs] [Times: user=0.00 sys=0.04, real=0.00 secs]
System.gc()
: 表示主动调用System.gc()触发GC [PSYoungGen: 5783K->720K(9216K)]
: 表示年轻带垃圾回收,回收前占用5783K,回收后占用720K,年轻带总可用内存9216K(年轻带一共10M,From Survivor 10%,To Survivor 10% ,Eden 80% 只有90%的空间是实际可用的) 10904K->9944K(19456K)
: 表示新生代和老年代总共内存使用情况,10904K是回收前总共使用量,9944K是回收后总共使用量,19456K(10M老年代+9M可用的年轻代)是总共可用量。这里可以看到总共内存回收后好像没啥效果,是因为大对象直接进入了老年代了,没有被回收,还占用着内存
第二条GC日志:
[Full GC (System.gc()) [PSYoungGen: 720K->0K(9216K)] [ParOldGen: 9224K->9577K(10240K)] 9944K->9577K(19456K), [Metaspace: 3275K->3275K(1056768K)], 0.0041171 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
明显的System.gc()同时触发了全栈回收,其他触发回收的场景还有内存分配失败也会触发,比如如下:
[GC (Allocation Failure) [PSYoungGen: 1536K->672K(17920K)] 1536K->680K(38400K), 0.0030734 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
总结下来内存情况都是类似:1536K->672K(17920K),第一个数字是回收前占用,第二个是回收后占用,括号里面是总内存