目录
问题报告
一日运维报告某应用JVM进程被OOM kill
[日期] 10-15-108-158 kernel: Out of memory: Kill process 23537 (java) score 846 or sacrifice child [日期] 10-15-108-158 kernel: Killed process 23537, UID 501, (java) total-vm:6458012kB, anon-rss:3364716kB, file-rss:112kB
可以看出进程是在虚拟内存用到6.46G左右,驻留内存用到3.36G左右被OOM kill掉的。
##问题分析
应用概况
该JVM是一个大数据接口程序,供后台报表应用查询一些预计算生成的各种数据,Linux虚拟机配置了6GB内存。应用使用了大量的第三方库连接MySQL,Kylin,Druid和ES等。同时JVM启动参数配置了XX:+HeapDumpOnOutOfMemoryError
选项。
初步分析
Java堆内存,MetaSpace等使用情况
从运维Zabbix系统中可以查出此JVM运行几周的堆内存和GC情况相当正常,并无堆内存泄露的情况。也并无hprof后缀的heap dump生成。
同时Meta Space也无任何泄露迹象。
监控记录显示Java线程数目也正常,并未发生线程数量剧增导致过量使用Thread Stack内存导致的泄露。
Java堆外内存分析
接着怀疑Java应用中是不是有第三方库使用了DirectByteBuffer操作堆外内存导致的泄露。但因为并未监控JVM堆外内存的使用情况,所以需要重新采集。
于是在重启的JVM启动参数中加入-XX:NativeMemoryTracking=detail
,并用crontab每小时运行jcmd {PID} VM.native_memory detail > nmt.$PID.`date '+%Y-%m-%d.%H:%M:%S'`.log
来记录JVM管辖内存的变化。也运行
pmap -x $PID > pmapx.$PID.`date '+%Y-%m-%d.%H:%M:%S'`.log
来记录操作系统进程内存段分布情况。
经记录,发现Native Memory Tracking(NMT)记录的JVM管理的内存情况均正常,包括Internal部分反映的堆外内存使用情况均正常,如下所示:
- Internal (reserved=13043KB, committed=13043KB) (malloc=13011KB #19159) (mmap: reserved=32KB, committed=32KB)
既然JVM管理的内存均正常,那就只能怀疑是进程的原生内存发生了泄露。
进程原生内存分析(Native Memory)
通过上一个步骤每小时记录的pmap内存使用和分段情况可以看出,进程使用的虚拟内存和驻留(RSS)内存不断地增加,一周虚拟内存增加了2GB多。
total kB 3174032 657612 637292
total kB 3174032 681068 660744
total kB 3174032 707084 686760
total kB 3175060 732216 711884
total kB 3175060 766008 745676
.......省略几万字
total kB 5006796 3231676 3218728
total k