在日常开发中,即使代码写得有多谨慎,免不了还是会发生各种意外的事件,比如服务器内存突然飙高,又或者发生内存溢出(OOM)。当发生这种情况时,我们怎么去排查,怎么去分析原因呢?

1. 什么是dump文件?

dump文件是一个进程或者系统在某一个给定的时间的快照。
dump文件是用来给驱动程序编写人员调试驱动程序用的,这种文件必须用专用工具软件打开。
dump文件中包含了程序运行的模块信息、线程信息、堆栈调用信息、异常信息等数据。
在服务器运行我们的Java程序时,是无法跟踪代码的,所以当发生线上事故时,dump文件就成了一个很关键的分析点。

2. 如何生成dump文件?

这里介绍两种方式:

一种是主动的
一种是被动的

方式一

主动生成dump文件。首先要查找运行的Java程序的pid。

使用top命令:

dump java 开启core java dump文件_java

然后使用jmap命令生成dump文件。file后面是保存的文件名称,1246则是java程序的PID。

jmap -dump:format=b,file=/Users/zhangjiguo/dump.hprof 1246

命令中的1246是需要dump文件的java进程的pid(括号及括号中的内容要记得删掉),可以通过top命令进行获取

方式二
其实在很多时候我们是不知道何时会发生OOM,所以需要在发生OOM时自动生成dump文件。
其实很简单,只需要在启动时加上如下参数即可。HeapDumpPath表示生成dump文件保存的目录。
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\tmp
我们还需要模拟出OOM错误,以此触发产生dump文件,首先写个接口:

private static Map<String, String> map = new HashMap<>();

@RequestMapping("/oom")
public String oom() throws Exception {
    for (int i = 0; i < 100000; i++) {
        map.put("key" + i, "value" + i);
    }
    return "oom";
}

然后在启动时设置堆内存大小为32M。
-Xms32M -Xmx32M
因为要后台启动,并且输出日志,所以最后启动命令就是这样:

java -Xms32M -Xmx32M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/zhangjiguo/dump.hprof  -jar auth-client-api-1.0.0.RELEASE.jar

然后请求oom的接口,查看日志,果然发生了OOM错误。
查看保存dump的目录,果然生成了对应的dump文件。

3. 如何查看dump文件?

这里我介绍使用Jprofiler,有可视化界面,功能也比较完善。

3.使用JProfiler打开

打开比较久,需耐心等待,千万不要点skip

dump java 开启core java dump文件_jar_02

4.查看Classes

dump java 开启core java dump文件_jvm_03

5.查看Reference

5.1 选择一个class或者biggest object

dump java 开启core java dump文件_jar_04

5.2 Use Slected Objects

dump java 开启core java dump文件_jvm_05

5.3 Incoming references

dump java 开启core java dump文件_dump java 开启core_06

  • incoming references 显示这个对象被谁引用
  • outcoming references 显示这个对象引用的其他对象

6.查看

dump java 开启core java dump文件_java_07

7.查看Graph

dump java 开启core java dump文件_linux_08

8.查看代码

dump java 开启core java dump文件_jvm_09

该方法主要用来导出数据报表,可以看出,当list数量太大时,就会导致OOM