如何診斷 Java 中的內(nèi)存泄露
每次我懷疑有內(nèi)存泄漏時(shí),我都要翻箱倒柜找這些命令。所以,這里總結(jié)一下以備后用:
首先,我用下面的命令監(jiān)視進(jìn)程:
- while ( sleep 1 ) ; do ps -p $PID -o %cpu,%mem,rss ; done
(如果有的話(huà)還有New Relic)
如果你看到內(nèi)存上升很快,可能是因?yàn)樘摂M機(jī)設(shè)置。如果你沒(méi)有明確指定JVM的內(nèi)存設(shè)置,它將設(shè)置默認(rèn)值給他們。要獲得默認(rèn)值,使用以下命令:
- java -XX:+PrintFlagsFinal -version | grep -i HeapSize
如果這些都不符合你所希望的,那么你就需要指定JVM的內(nèi)存設(shè)置??梢杂孟旅娴拿钤O(shè)置最小和***堆大小:
- java -Xms128m -Xmx256m
盡管你有了合理的內(nèi)存設(shè)置,也可以監(jiān)控進(jìn)程,但你仍然可能看到內(nèi)存隨時(shí)間增加。為了進(jìn)一步探究原因,你可以使用下面的命令查看對(duì)象實(shí)例的直方圖:
jmap -histo $PID
如果仍然沒(méi)有足夠的信息,那么可以用以下命令進(jìn)行堆轉(zhuǎn)儲(chǔ):
jmap -dump:format=b,file=/tmp/dump1.hprof $PID
通常,我會(huì)用兩個(gè)堆轉(zhuǎn)儲(chǔ),然后使用下面的jhat命令比較它們:
jhat -baseline /tmp/dump1.hprof /tmp/dump2.hprof
這個(gè)命令會(huì)啟動(dòng)一個(gè)HTTP服務(wù)器,你可以用它來(lái)探索這兩個(gè)堆轉(zhuǎn)儲(chǔ)之間的差值。在默認(rèn)情況下,HTTP服務(wù)器啟動(dòng)7000端口,你可以在瀏覽器中訪(fǎng)問(wèn)該端口。
如果你有防火墻,可以通過(guò)SSH訪(fǎng)問(wèn),那么你可以通過(guò)如下命令連接該端口:
ssh -L 7000:localhost:7000 $HOST
向下滾動(dòng)到***頁(yè)的底部,你會(huì)看到兩個(gè)有用的鏈接:
這將給你展示在不同堆轉(zhuǎn)儲(chǔ)之間所有“新”的實(shí)例,應(yīng)該對(duì)你檢測(cè)泄漏來(lái)自哪里有些幫助。截圖如下:
然后你就擁有了一個(gè)神奇命令行的快速查看目錄,以便于你需要診斷內(nèi)存泄漏時(shí)使用(然而我總是忘記)。