前言
- 最近线上系统基本安然无事。本着没事找事的原则,就找运维打了份线上GC的dump文件,用来分析学习一波。然后就接触到了Memory Analyzer分析工具
下载安装
- Memory Analyzer下载地址
- 解析下载安装包后,直接运行MemoryAnalyzer程序文件即可:
构建dump文件
- 本次示例就自建生成一个Java版dump文件,先构造一个实体对象:
@Data
public class User {
private String name;
private String phone;
}
- 构造一个main方法,里面遍历向集合中放入实体对象:
public class Demo1 {
public static void main(String[] args) {
List<User> list = new ArrayList<>();
for (int i = 0; i < 10000000; i++) {
User user = new User();
user.setName("小猪");
user.setPhone("15222222222");
list.add(user);
}
System.out.println("添加完成");
}
}
- 然后添加启动JVM参数打印GC日志和输出dump文件:
-Xms10m -Xmx20m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=F:\hporf
- 最后启动运行main方法后,再控制台会打印GC日志也会生成dump文件:
[0.002s][warning][gc] -XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead.
[0.006s][info ][gc] Using G1
[0.007s][info ][gc,init] Version: 17.0.2+8-LTS-86 (release)
[0.007s][info ][gc,init] CPUs: 16 total, 16 available
[0.007s][info ][gc,init] Memory: 16291M
[0.007s][info ][gc,init] Large Page Support: Disabled
[0.007s][info ][gc,init] NUMA Support: Disabled
[0.007s][info ][gc,init] Compressed Oops: Enabled (32-bit)
[0.007s][info ][gc,init] Heap Region Size: 1M
[0.007s][info ][gc,init] Heap Min Capacity: 10M
[0.007s][info ][gc,init] Heap Initial Capacity: 10M
[0.007s][info ][gc,init] Heap Max Capacity: 20M
[0.007s][info ][gc,init] Pre-touch: Disabled
[0.007s][info ][gc,init] Parallel Workers: 13
[0.007s][info ][gc,init] Concurrent Workers: 3
[0.007s][info ][gc,init] Concurrent Refinement Workers: 13
[0.007s][info ][gc,init] Periodic GC: Disabled
....
[0.247s][info ][gc,ergo ] Attempting maximum full compaction clearing soft references
[0.247s][info ][gc,task ] GC(29) Using 2 workers of 13 for full compaction
[0.247s][info ][gc,start ] GC(29) Pause Full (G1 Compaction Pause)
[0.247s][info ][gc,phases,start] GC(29) Phase 1: Mark live objects
[0.261s][info ][gc,phases ] GC(29) Phase 1: Mark live objects 13.960ms
[0.261s][info ][gc,phases,start] GC(29) Phase 2: Prepare for compaction
[0.263s][info ][gc,phases ] GC(29) Phase 2: Prepare for compaction 1.940ms
[0.263s][info ][gc,phases,start] GC(29) Phase 3: Adjust pointers
[0.268s][info ][gc,phases ] GC(29) Phase 3: Adjust pointers 4.387ms
[0.268s][info ][gc,phases,start] GC(29) Phase 4: Compact heap
[0.270s][info ][gc,phases ] GC(29) Phase 4: Compact heap 2.186ms
[0.270s][info ][gc,heap ] GC(29) Eden regions: 0->0(1)
[0.270s][info ][gc,heap ] GC(29) Survivor regions: 0->0(1)
[0.270s][info ][gc,heap ] GC(29) Old regions: 16->16
[0.270s][info ][gc,heap ] GC(29) Archive regions: 0->0
[0.270s][info ][gc,heap ] GC(29) Humongous regions: 3->3
[0.270s][info ][gc,metaspace ] GC(29) Metaspace: 775K(896K)->775K(896K) NonClass: 716K(768K)->716K(768K) Class: 59K(128K)->59K(128K)
[0.270s][info ][gc ] GC(29) Pause Full (G1 Compaction Pause) 18M->18M(20M) 22.807ms
[0.270s][info ][gc,cpu ] GC(29) User=0.03s Sys=0.00s Real=0.02s
java.lang.OutOfMemoryError: Java heap space
[0.270s][info ][gc,marking ] GC(25) Concurrent Mark Abort
[0.270s][info ][gc ] GC(25) Concurrent Mark Cycle 55.477ms
Dumping heap to F:\hporf\java_pid14460.hprof ...
Heap dump file created [31773704 bytes in 0.048 secs]
[0.319s][info ][gc,heap,exit ] Heap
[0.320s][info ][gc,heap,exit ] garbage-first heap total 20480K, used 18573K [0x00000000fec00000, 0x0000000100000000)[0.320s][info ][gc,heap,exit ] region size 1024K, 1 young (1024K), 0 survivors (0K)
[0.320s][info ][gc,heap,exit ] Metaspace used 787K, committed 960K, reserved 1056768K
[0.320s][info ][gc,heap,exit ] class space used 60K, committed 128K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.Arrays.copyOf(Arrays.java:3512)
at java.base/java.util.Arrays.copyOf(Arrays.java:3481)
at java.base/java.util.ArrayList.grow(ArrayList.java:237)
at java.base/java.util.ArrayList.grow(ArrayList.java:244)
at java.base/java.util.ArrayList.add(ArrayList.java:454)
at java.base/java.util.ArrayList.add(ArrayList.java:467)
at com.zrh.web.demo.Demo1.main(Demo1.java:14)
- 上述的GC日志就不在本篇文章解析了,读者可以自行下去解析,以下是生成的dump文件。
MemoryAnalyzer解析
- 点击进入MemoryAnalyzer可视界面后,选择点击File,点击Open Heap Dump...,选择刚才生成的dump文件:
- Details:表示当前通过dump文件解析出来的堆得基本信息;
- Biggest Objects by Retained Size:表示内存使用较大线程信息;
- Histogram:表示当前内存中每个类的实例数:
- Dominator Tree:表示排列出最大的对象以及其所占百分比(堆查找内存溢出很有帮助):
-
通过上述的几个列表基本也可以推断出内存溢出的原因,就是main线程里创建了较多的com.zrh.web.demo.User对象;
-
除了通过上述的数据指标可以让开发人员预估问题的所在外,MemoryAnalyzer也已经帮开发人员预估的内存问题的可能原因:
- 然后点击Details,选择list objects -- with outgoing references:(查看这个对象持有的外部对象引用)
- 可以找到在list集合中存在50万个对象,就是最后导致系统内存溢出原因。
最后
- 虚心学习,共同进步-_-