GC日志分析

VM参数

1、在控制台打印出每次GC信息:

1
-XX:+PrintGCDetails

2、在发生OOM时打印出堆栈信息:

1
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/chuan/

OOM代码

发生OOM测试程序代码,也可以自行编写,运行VM参数(-Xms1m -Xmx1m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/chuan/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class OOMDemo {

private static final int K = 1024;
private static final int M = K * K;
private static final int G = K * M;
private static final int ALIVE_OBJECT_SIZE = 32 * M;

public static void main(String[] args) {
int length = ALIVE_OBJECT_SIZE / 64;
ObjectOf64Bytes[] array = new ObjectOf64Bytes[length];
for (long i = 0; i < G; i++) {
array[(int) (i % length)] = new ObjectOf64Bytes();
}
}
}

class ObjectOf64Bytes {
long placeholder0;
long placeholder1;
long placeholder2;
long placeholder3;
long placeholder4;
long placeholder5;
}

Minor GC日志

[GC --[PSYoungGen: 447K->447K(1024K)] 709K->956K(1536K), 0.0031459 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

下面来解析这一段信息,其实很简单,不用硬记,按顺序从左到右:

  • GC:表示这是发生了GC

  • PSYoungGen:GC类型,此处表示新生代内存发生了GC;

  • 447K->447K:->前面的447K表示GC前新生代内存占用,->后面的447K表示GC后新生代内存占用(此处是分毫未被回收,那你执行个骡子,浪费 0.0031459秒);

  • (1024K):1024K表示新生代总共大小,看得出来是1M,可以回头看一下VM参数配置;

  • 709K->956K:709K表示GC前JVM堆内存使用,956表示GC后JVM堆内存使用(硌老子的,GC后还变多了);

  • (1536K):1536K表示JVM堆内存总大小;

  • 0.0031459 secs:本次GC耗时(看得出还是很快的);

  • user:GC用户耗时;

  • sys:GC系统耗时;

  • real:GC实际耗时。

Full GC日志

[Full GC [PSYoungGen: 447K->197K(1024K)] [ParOldGen: 508K->494K(512K)] 956K->692K(1536K), [Metaspace: 3179K->3179K(1056768K)], 0.0069504 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

  • Full GC:GC类型;

  • [PSYoungGen: 447K->197K(1024K)] :Young区,447K表示GC前Young区内存占用,197K表示GC后Young区内存占用,1024K表示Young区总大小;

  • [ParOldGen: 508K->494K(512K)] :Old区,508K表示GC前Old区内存占用,494K表示GC后Old区内存占用,512K表示Old区总大小;

  • 956K->692K(1536K):956K表示GC前JVM堆内存使用,692K表示GC后JVM堆内存使用,1536K表示JVM堆内存总大小;

  • [Metaspace: 3179K->3179K(1056768K)]:元空间,3179K表示GC前后元空间的使用,1056768K表示元空间的总大小(使用VM参数 -XX:-UseCompressedClassPointers -XX:MetaspaceSize=50M指定元空间的总大小);

  • 0.0069504 secs:本次GC耗时(看得出还是很快的);

  • user:GC用户耗时;

  • sys:GC系统耗时;

  • real:GC实际耗时。

规律

[名称:GC前内存->GC后内存(总内存)]

1
2
3
4
5
6
7
8
Heap
PSYoungGen total 2560K, used 60K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
eden space 2048K, 2% used [0x00000000ffd00000,0x00000000ffd0f038,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 7168K, used 736K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
object space 7168K, 10% used [0x00000000ff600000,0x00000000ff6b8128,0x00000000ffd00000)
Metaspace used 3328K, capacity 4112K, committed 4352K, reserved 8192K

解析上述:

PSYoungGen total = eden space + from space,内存地址eden+from+to

ParOldGen GC前后老年代的内存变化