最近有一個(gè)java服務(wù)的堆內(nèi)存溢出,然后僵死了,在重啟服務(wù)之前用jmap命令生成了一份dump文件便于后面分析。
生成dump文件的命令:
jmap -dump:format=b,file=20170307.dump 16048
file后面的是自定義的文件名,最后的數(shù)字是進(jìn)程的pid。
查看整個(gè)JVM內(nèi)存狀態(tài) jmap -heap [pid]要注意的是在使用CMS GC 情況下,jmap -heap的執(zhí)行有可能會(huì)導(dǎo)致JAVA 進(jìn)程掛起 查看JVM堆中對(duì)象詳細(xì)占用情況jmap -histo [pid] 導(dǎo)出整個(gè)JVM 中內(nèi)存信息jmap -dump:format=b,file=文件名 [pid]
使用jvisualvm來分析dump文件:
jvisualvm是JDK自帶的Java性能分析工具,在JDK的bin目錄下,文件名就叫jvisualvm.exe。
jvisualvm可以監(jiān)控本地、遠(yuǎn)程的java進(jìn)程,實(shí)時(shí)查看進(jìn)程的cpu、堆、線程等參數(shù),對(duì)java進(jìn)程生成dump文件,并對(duì)dump文件進(jìn)行分析。
像我這種從服務(wù)器上dump下來文件也可以直接扔給jvisualvm來分析。
使用方式:直接雙擊打開jvisualvm.exe,點(diǎn)擊文件->裝入,在文件類型那一欄選擇堆,選擇要分析的dump文件,打開。
裝入之后在界面右側(cè)的概要、類等選項(xiàng)卡可以看到生成dump文件當(dāng)時(shí)的堆信息:
可以看到,dump文件里記錄的堆中的實(shí)例,總大小大概300M左右,(用第一行的實(shí)例大小除以百分比就能算出來),和JVM默認(rèn)的新生代的大小差不多,遠(yuǎn)小于JVM中設(shè)置的最大堆內(nèi)存,也就是說,dump文件里記錄的并不是實(shí)例大小達(dá)到最大堆內(nèi)存時(shí)的狀態(tài)。
為了驗(yàn)證一下,我自己在本地模擬了一下堆內(nèi)存溢出的情形,并用jvisualvm監(jiān)控
我本地設(shè)置的最大堆內(nèi)存是800M左右,代碼里面是往一個(gè)List里面瘋狂加數(shù)據(jù),直到撐爆堆內(nèi)存,得到的監(jiān)控內(nèi)容是這樣的:
分析:紅框框出的部分是發(fā)生堆內(nèi)存溢出時(shí)的情形,已使用的堆大?。ㄋ{(lán)色部分)并沒有增長(zhǎng)特別明顯,但是申請(qǐng)的堆的大?。S色部分)從默認(rèn)的400多兆急速上漲,漲到800M,然后內(nèi)存溢出,然而使用的堆大小依然沒怎么增長(zhǎng)。
所以,dump文件中的實(shí)例列表其實(shí)是反映了使用的堆的情況,而使用的堆內(nèi)存并沒有達(dá)到預(yù)先設(shè)置的最大堆內(nèi)存,只是在申請(qǐng)堆內(nèi)存的過程中超出了預(yù)先設(shè)置的最大堆內(nèi)存,然后內(nèi)存溢出。