JVM实战02(堆内存溢出)
目录
问题简介
堆内存溢出在实际项目上会是一个经常遇到的问题。如何定位?如何解决?
演示代码
1.配置JVM参数
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
当发生堆内存溢出时转存内存快照。
在一些极端情况下,堆内存溢出可能直接导致线程崩溃。
2.模拟代码
public class OOMTest
{
private static List<String> list = new ArrayList<>();
public static void main(String[] args) {
while (true)
{
list.add("test");
}
}
}
死循环往列表里添加元素,直到内存溢出。
使用MAT分析hprof文件
1.打开文件
Workbench-->File-->Open Heap Dump:
java_pid12532.hprof
打开文件后有一个初始化选项,直接关闭即可。
2.分析内存文件
1.从上图红色箭头1可以直接看出,Object对象占用了7M,其它占用很少,
这明显是不对。
2.我们接着点击箭头2,Leak Suspects(泄漏疑点)
1.One instance of "java.lang.Object[]" loaded by "<system class loader>"
occupies 7,292,936 (92.61%) bytes.
系统加载时object数组分配占用了2.61%
2.点击Details查看详细报告
1.红色箭头1,代表支配树积累的对象:
。我们可以看到java.lang.Object[1823230]对象积累最多
。左键点击java.lang.Object这一行-->List Objects-->
.with outgoing references //我引用了谁
.with incoming references //谁引用了我,点击就可以
查看最终哪一行代码导致的
会发现是OOMTest这个类调用,我们可以查看类里的代码。
2.当然也可以点击红色箭头Thrad Details,查看线程详细信息。
我们也可以从这里线程调用栈查看到问题。
堆内存溢出场景
1.内存泄漏(如上步骤,使用Mat分析内存文件)
找到这个泄漏的对象是通过怎样的路径,跟哪个对象关联,
从而导致这个对象没有被回收掉。一般找到这个对象的创建
位置,我们就能发现问题所在。
2.非内存泄漏
。经过分析发现,目前内存对象必须都是存活的
考虑调大机器内存,考虑对象生命周期是否太长。