堆溢出
# 堆溢出
# 报错信息
报错信息:java.lang.OutOfMemoryError: Java heap space
# 案例模拟
一个Spring Boot应用,主要如下,详见案例代码。请求 http://localhost:8080/add
/**
* 案例1:模拟线上环境OOM
*/
@RequestMapping("/add")
public void addObject(){
System.err.println("add"+peopleSevice);
ArrayList<People> people = new ArrayList<>();
while (true){
people.add(new People());
}
}
JVM参数配置:
-Xms80M
-Xmx80M
-XX:MetaspaceSize=64m
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:log/gc-oomHeap.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=heap/heapdump.hprof
运行结果:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210) ~[na:1.8.0_131]
at java.util.Arrays.copyOf(Arrays.java:3181) ~[na:1.8.0_131]
at java.util.ArrayList.grow(ArrayList.java:261) ~[na:1.8.0_131]
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235) ~[na:1.8.0_131]
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227) ~[na:1.8.0_131]
关于如何获取dump文件详见:获取dump文件。注意,于我们当前设置的内存比较小,所以该文件比较小,但是正常在线上环境,该文件是比较大的,通常是以G为单位。
# 分析解决
VisualVM分析dump文件:
MAT分析dump文件:
GCEasy分析log文件:
原因:
- 代码中可能存在大对象分配
- 可能存在内存泄漏,导致在多次GC之后,还是无法找到一块足够大的内存容纳当前对象。
解决方案:
- 检查是否存在大对象的分配,最有可能的是大数组分配
- 通过jmap命令,把堆内存dump下来,使用MAT等工具分析一下,检查是否存在内存泄漏的问题
- 如果没有找到明显的内存泄漏,使用 -Xmx 加大堆内存
- 还有一点容易被忽略,检查是否有大量的自定义的 Finalizable 对象,也有可能是框架内部提供的,考虑其存在的必要性
上次更新: 5/28/2023, 10:57:53 PM