工欲善其事必先利其器!只有对Java服务应用的内存使用情况充分了解,才能保持其健壮性。Java对象的内存分布情况可以通过JDK自带的工具jmap
获取,对内存情况的分析JDK也提供了相应的工具jhat
。由于jhat
使用起来并不友好,更多的时候用的是更为强大且直观的内存分析神器MAT
。
- 基本用法
- 真实案例分享
- 总结
基本用法
- 下载MAT。
- 获取内存dump文件。
- 运行
MAT
分析文件。
下载安装MAT是相当简单的,这里就不过多描述。至于如何获取内存的dump文件?一般有三种方式:其一我们可以通过jmap
去获取当前Java进程的堆内存信息:
# 1. 直接查看对象分布
$ jmap -histo ${PID}
# 2. 使用jmap生成堆内存转储快照
# format=b:二进制 dump.hprof:文件名
$ jmap -dump:live,format=b,file=dump.hprof ${PID}
# 记录堆内存所有对象的快照放到文件里去了,供后续MAT分析
第二种方式,也是每个应用必不可少的兜底方式,就是设置JVM选项,使应用能在任何时候发生OutOfMemoryError
的时候都能自动生成一份dump文件[保留事故现场]。
# JVM 设置
-XX:+HeapDumpOnOutOfMemoryError
第三种方式是通过MAT直连本机Java进程获取,点击Acquire Heap Dump Dialog
,应用会将本机运行Java进程的列表展示出来,选择一个对应Java进程即可。由于我们的程序一般运行在Linux的堡垒机上[无论是测试还是生产环境],这个功能也基本上很少用到。
如何使用MAT进行内存分析呢?
通过我们上面JVM参数的设置,一旦我们的应用出现OOM
的错误,那么当时对象内存分布的快照文件会自动创建,我们只需要将这个文件从服务器传到本地进行分析即可[一般用sftp工具]。通过MAT打开该文件的时候需要注意一点:OOM出现的时候,dump文件都会非常大,这里需要设置一下MAT的MemoryAnalyzer.ini
配置:
# MemoryAnalyzer.ini
-Xmx1024m #默认只有1GB,按需修改。
Leak Suspects
Leak Suspects
这个报告信息是最直观可以分析出内存泄漏的地方。如下图,MAT会将可能出现内存泄漏的问题点的信息展示出来:包括大对象内存分布饼状图、线程信息、内存泄漏对象的大小。有经验的工程师通过这一点基本上就可以直接去看代码找到问题的所在了。
Histogram
Histogram[直方图]展示的是每个class实例个数、Shallow Heap和Retained Heap。Shallow Heap指的是每个实例占用的内存[如一个Object对象需要64个bits];Retained Heap
则是每个实例引用到其他对象的总大小。Retained Heap
的含义是,当某个对象回收的时候,与此同时它所引用的对象也会回收,所回收的内存大小就是这个Retained Heap。一般生产中运行的应用,需要关注的是那些自定义的类所创建的实例数量以及通过框架反射创建的实例数量是否正常。
Dominator Tree
直方图[Dominator Tree]能给出的信息是通过类的名称统计的,要弄清楚对象真实的内存分布情况需要用到MAT另外的一个分析方式:Dominator Tree(支配树)。支配树列出每个对象(Object instance)与其引用关系的树状结构,还包含了占有多大内存,所占百分比。
通过下图我们就很容易看出来这里导致OOM的原因是:一个名为doom-collection
的线程下有一个ArrayList
对象包含了9个超大的Character数组
对象。
Thread_overview
线程总览[Thread_overview]功能也相当使用,它可以将线程信息、局部变量、方法栈信息以及内存信息展示出来。开发人员可将问题直接定位到实际代码行数。
以上这些功能足以应对测试及生产中出现的OOM问题的排查。接下来讲述一个我们遇到的真实的OOM案例。
真实案例分享
该案例虽然是发生在测试环境,但是其关联影响也是不小的。由于我们的系统是一个平台性的系统,很多关联方需要在我们测试环境做测试,所以我们的测试环境基本上都要保持一个稳定的状态,一旦环境出问题各方的投诉就会蜂拥而至。
某天,测试跑过来说FAT环境很卡,请求时不时超时。查看日志,发现正常运行了几个月的系统第一次出现了OOM!dump文件拉出来一看,问题显而易见:有一个自动化测试框架的线程对象占了饼状图80%的内存。最后问题的定位是测试工程师新加了自动化测试框架,然而相关参数设置有问题导致对象创建过多,最总内存溢出。解决方法:修改参数,重新启动应用,服务恢复正常。
总结
MAT非常小巧也非常实用,一方面使用它能迅速找到OOM的问题所在,另一方面通过它可以清晰的了解整个应用的内存分布情况。OOM是非常严重的问题,在测试阶段就应该特别注意。尤其是压测阶段,可以通过上面的分析工具及方法查看并分析应用运行时的对象内存分布情况,尽早的发现问题的所在,这样才能保证生产环境下应用的健壮。