在很久之前的项目上线出现了一次OOM,当时凭着jmap和VisualVM。定位了问题并解决问题。但是因为时间久远,怕以后忘记定位这种堆内存溢出的定位步骤,所以今天自己造了一个OOM,来复习并记录定位步骤。
首先制造OOM的代码如下:
@Test
public void test() {
List<DvcDevice> dvcDevices = new ArrayList<>();
while (true) {
dvcDevices.add(new DvcDevice());
}
}
用junit启动后,通过VisualVM查看堆栈,cpu等信息,结果如下图所示:
堆内存一直在升高,当堆内存无法申请到内存时,就会抛出OOM异常。
接下来,通过VisualVM工具可以看到该应用的PID,然后打开CMD通过jmap -dump:live,format=b,file=/my.dump pid,打印该应用堆空间中存活的对象信息。那么dump文件怎么打开呢?
同样使用 VisualVM(太好用了)如下图所示:
装入你的dump文件。然后在下图所示的模块中,就能看到所有对象的内存暂用率:
可以看出是DvcDevice这个类暂用了大部分堆内存,结合上面的代码和OOM异常抛出的代码指向,就能知道问题所在。