Java —— 内存泄露排查
最近發(fā)現(xiàn)服務(wù)器內(nèi)存使用持續(xù)增長且增長速率大,懷疑是內(nèi)存泄露導(dǎo)致的。
最終定位到是因為程序中存在線程池頻繁創(chuàng)建但未銷毀問題導(dǎo)致線程泄露,進而影響內(nèi)存使用增長。
Tips:本文不記錄排錯過程,只記錄可疑點及排錯命令。
1. 套路
① 查看內(nèi)存使用,對相隔一段時間的應(yīng)用內(nèi)存使用情況進行對比(top命令等),確認(rèn)內(nèi)存存在緩慢上升的情況
② jstat -gccapacity 【pid】查看JVM各部分內(nèi)存使用增長是否符合top命令展示的應(yīng)用內(nèi)存使用增長。
-
如果符合,則使用MAT工具分析JVM堆棧情況,對比隔一段時間的堆棧對象增長情況,對于增加的對象進行內(nèi)存泄露排查。
-
如不符合,這說明內(nèi)存使用很大概率不是JVM堆棧導(dǎo)致的,可能程序中使用了堆外內(nèi)存,堆外內(nèi)存持續(xù)增長的這種情況不容易排查,最好開啟JVM的NMA功能,使用jcmd命令對堆外內(nèi)存進行分析。
2. 常見堆外泄露
- JNI
- gzip
- 線程棧
- 不良代碼
- ThreadLocal
- NIO directbuffer泄漏
3. Linux內(nèi)存相關(guān)概念
-
used區(qū):應(yīng)用實際占用內(nèi)存,在+/-buffer計算方式下,used區(qū)=實際已用內(nèi)存。而在Mem計算方式下,used=實際已有+Buffer+Cache (原因是Buffer和Cache在應(yīng)用需要時會釋放出應(yīng)用所需大小供應(yīng)用使用,但是不會全部釋放)
-
free區(qū):剩余空閑內(nèi)存大小,未被應(yīng)用used或被系統(tǒng)用于緩存(Cache/Buffer)的內(nèi)存部分。
-
Cached區(qū):這里的cache指Linux內(nèi)存中的:Page cache。Page cache主要用來作為文件系統(tǒng)上的文件數(shù)據(jù)的緩存來用,尤其是針對當(dāng)進程對文件有read/write操作的時候。如果你仔細(xì)想想的話,作為可以映射文件到內(nèi)存的系統(tǒng)調(diào)用:mmap是不是很自然的也應(yīng)該用到page cache?在當(dāng)前的系統(tǒng)實現(xiàn)里,page cache也被作為其它文件類型的緩存設(shè)備來用,所以事實上page cache也負(fù)責(zé)了大部分的塊設(shè)備文件的緩存工作。
-
Buffer區(qū):Buffer cache則主要是設(shè)計用來在系統(tǒng)對塊設(shè)備進行讀寫的時候,對塊進行數(shù)據(jù)緩存的系統(tǒng)來使用。這意味著某些對塊的操作會使用buffer cache進行緩存,比如我們在格式化文件系統(tǒng)的時候。
一般情況下兩個緩存系統(tǒng)是一起配合使用的,比如當(dāng)我們對一個文件進行寫操作的時候,page cache的內(nèi)容會被改變,而buffer cache則可以用來將page標(biāo)記為不同的緩沖區(qū),并記錄是哪一個緩沖區(qū)被修改了。這樣,內(nèi)核在后續(xù)執(zhí)行臟數(shù)據(jù)的回寫(writeback)時,就不用將整個page寫回,而只需要寫回修改的部分即可。 -
total:內(nèi)存總量
4. Linux查看內(nèi)存相關(guān)命令
① free / free -m / free -g
相關(guān)參數(shù)說明
② cat /proc/meminfo
③ jstat -gccapacity 【pid】 —— 查看堆內(nèi)存使用情況,包括元空間,老年代,年輕代
- NGCMN:新生代最小容量 - NGCMX:新生代最大容量 - NGC:當(dāng)前新生代容量 - S0C:第一個幸存區(qū)大小 - S1C:第二個幸存區(qū)的大小 - EC:伊甸園區(qū)的大小 - OGCMN:老年代最小容量 - OGCMX:老年代最大容量 - OGC:當(dāng)前老年代大小 - OC:當(dāng)前老年代大小 - MCMN:最小元數(shù)據(jù)容量 - MCMX:最大元數(shù)據(jù)容量 - MC:當(dāng)前元數(shù)據(jù)空間大小 - CCSMN:最小壓縮類空間大小 - CCSMX:最大壓縮類空間大小 - CCSC:當(dāng)前壓縮類空間大小 - YGC:年輕代gc次數(shù) - FGC:老年代GC次數(shù)④ top / top 【pid】/ top -Hp【pid】
⑤ ps -aux | grep 【pid】
⑥ jmap命令
jmap -heap 【pid】 —— 查看JVM呈現(xiàn)堆棧使用
jmap -histo 【pid】—— 查看堆中對象數(shù)量和大小
jmap -dump:format=b,file=heapdump pid:將內(nèi)存使用的詳細(xì)情況輸出到文件
⑦ jcmd 【pid】 GC.heap_dump 【輸出路徑】 —— 查看GC堆棧,同jmap -dump | jcmd [pid] VM.native_memory
⑧ watch -n 1 ps v 【pid】—— 動態(tài)查看進程內(nèi)存使用,每秒刷新
⑨ strace -f -e"brk,mmap,munmap" -p 【pid】 追蹤進程內(nèi)存使用
⑩ pmap -x [pid] 與 diff pmap文件1 pmap文件2 -y -w
資料:
https://elasticsearch.cn/article/178
https://my.oschina.net/alchemystar/blog/1603817
https://www.cnblogs.com/xiaohanlin/p/12888396.html
https://blog.csdn.net/hellozhxy/article/details/95203462
總結(jié)
以上是生活随笔為你收集整理的Java —— 内存泄露排查的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sarcasm Detection wi
- 下一篇: java美元兑换,(Java实现) 美元