配置 jvm 参数,内存溢出时会自动HeapDump(指定 dump 文件路径是可选的)
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home
或者用 jmap
jmap -dump:format=b,file=<filename.hprof> <pid>
必要时将dump文件从容器中拷贝到物理机
# docker cp <container_name>:<container_path> <local_path>
docker cp 4d09feaf6483:/home/java_pid8.hprof /work
# kubectl cp default/POD_NAME:bin/FILE_NAME /Users/username/FILE_NAME
kubectl cp default/docker-sample-799db6c8d7-mqwww:/home/java_pid8.hprof /home/K8S/java_pid8.hprof
MAT(Memory Analyzer Tool) 定位堆内存溢出问题
下载安装 MAT(Memory Analyzer Tool),这个软件是 eclipse 基金会搞的。
打开 MAT -> File -> Open Heap Dump -> 选择对应 .hprof 文件

点击查看 leak suspects(泄露嫌疑人),分析内存泄露

点击这个 Problem Suspect1 的 Details,在 Shortest Paths To the Accumulation Point (到达累积点的最短路径)点击 java.lang.Object[360145] ,选择 Lists objects -> with incoming references,查看这个对象被引用情况。


可以看到,是被 oomList 引用了,所以就会怀疑是 oomList 对象导致的内存溢出,然后去对应代码里查看。
/**
* 堆内存溢出
*
* -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
*/
@Component
public class HeapOOMService {
private AtomicInteger index = new AtomicInteger(0);
private List<User> oomList = new ArrayList<>();
public void heapOOM() {
while (true) {
oomList.add(new User(index.getAndAdd(1)));
}
}
private static class User {
private int id;
public User(int id) {
this.id = id;
}
}
}
此外,点击 See stacktrace 可以查看调用栈信息,从调用栈信息中,也可以找到是哪里出问题。


VisualVM 定位堆内存溢出问题
VisualVM JDK8 内置,直接输入命令 jvisualvm 即可,JDK11以后需要下载
JDK8版本 VisualVM
打开 VisualVM -> File -> load -> 选择对应 .hprof 文件 -> 点击类 -> 在实例数最多的类名上右击 -> 选择在实例视图中展示 -> 查看引用



新版本 VisualVM 2.1.5(JDK11不内置了)
http://visualvm.github.io/download.html
打开 VisualVM -> File -> load -> 选择对应 .hprof 文件 -> Instances by Size -> 右击 java.lang.Object 数组 -> 点击 Open in New Tab -> 展开 references


堆内存溢出的场景
- 内存泄露
- 非内存泄露
业务代码中可能的内存溢出改造
pageSize 不做限制可以无限大的话,可能导致内存溢出。
本文介绍了如何使用MAT和VisualVM工具来定位Java堆内存溢出问题。通过配置JVM参数获取Heap Dump,然后在MAT中分析泄露嫌疑人,以及在不同版本的VisualVM中查看对象引用和调用栈信息,从而找出内存泄漏的源头。同时讨论了内存溢出的场景和业务代码中可能的内存溢出改造策略。
1万+

被折叠的 条评论
为什么被折叠?



