因为请求量、环境不同的原因,平时 Java 应用在本地上无法完全复现线上的问题,排查相关问题需要导出堆来分析内存。
产品部署到现场后,随着使用时长、请求量的原因出现了 GC 耗时长、次数频繁的问题.
导出内存快照
排查问题需要导出生产环境的内存堆快照,导出分为手动方式以及自动方式,导出堆快照前需要注意以下事项:
自动导出内存堆快照时,在写Heap Dump文件前通常会触发一次Full GC,所以Heap Dump文件保存的都是Full GC留下的对象信息。
生成dump文件比较耗时,大内存镜像生成dump文件需要更长时间,需要耐心等待。导出的文件体积较大,需要注意硬盘空间是否充足,避免因为硬盘空间不足而引发其他故障。
手动导出
可以使用 JDK 自带的 jmap
命令手动导出。
1 | jmap -dump:format=b,file=<filename.hprof> <pid> |
说明:
<filename.hprof>
中的filename是导出文件的名称,而.hprof是后缀名,方便后续使用MAT等工具选取文件分析,也可以忽略文件后缀。<pid>
是进程ID,可以使用ps
或者jps
命令查看应用进程ID。format=b
表示生成的是标准的dump文件,用来进行格式限定-dump:live
指只dump出存活的对象
例子:
1 | [hadoop_admin@hadoop1 bin]$ jps |
等待导出完成后,拉取快照文件回本地分析即可,堆文件较大拉回本地可能比较麻烦,可以使用 tar
命令压缩,实测普通压缩效果不明显,可使用gzip压缩。例:
1 | [hadoop_admin@hadoop1 bin]$ tar -czvf DataNodeDump.tar.gz DataNodeDump.hprof |
自动导出
某次在拉取应用日志排查异常堆栈信息时发现应用曾经 OOM 过(Exception in thread "main" java.lang.OutOfMemoryError
)。
当应用发生Full GC或者OOM退出时,内存信息随着应用的退出而烟消云散, 重现OOM的情况比较困难(耗时、或无法重现)。这时候就需要自动导出内存堆快照了,可在启动应用时增加JVM参数。
1 | -XX:+HeapDumpOnOutOfMemoryError #在应用OOM时,导出应用程序内存堆快照 |
分析内存快照
将内存堆快照拉取回本地后,使用分析工具进行内存使用分析,如 JDK 自带的 jhat
,或者Eclipse MemoryAnalyzer Tool(MAT) 、 VisualVM 等等。
其中 JDK 自带的 jhat
命令在 JDK9 之后已经被移除了。MAT 的内存泄漏推断功能算比较强大的工具。以下介绍MAT分析过程
启动MAT可能遇到的错误
Parsing heap dump from ‘xx.hprof‘ Java heap space
错误原因:堆内存文件大于MAT工具的运行时内存
修改 MemoryAnalyzer.ini
文件,将 -Xmx
参数调整为大于堆内存文件的大小即可
JDK版本不对
如 An error has occurred. See the log file null.
或者 Version 1.8.0 381 of the JVM is not suitable for this product. Version: 17 or greater
修改 MemoryAnalyzer.ini
文件,增加 -vm
参数指定高版本JDK(JDK11、17)路径