這篇文章將為大家詳細(xì)講解有關(guān)JAVA中怎么排查內(nèi)存泄漏,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
創(chuàng)新互聯(lián)建站是一家專業(yè)提供黃平企業(yè)網(wǎng)站建設(shè),專注與成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)、H5高端網(wǎng)站建設(shè)、小程序制作等業(yè)務(wù)。10年已為黃平眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡(luò)公司優(yōu)惠進(jìn)行中。
內(nèi)存泄漏
內(nèi)存泄漏(Memory Leak)是指程序中一個對象或變量無法回收,一直保存在內(nèi)存中。這樣的對象或變量一直累計,最終導(dǎo)致內(nèi)存溢出(Out Of Memory)。
內(nèi)存泄漏原因
內(nèi)存泄漏大概有以下幾個原因
1.靜態(tài)集合存放對象
長周期對象持有了短周期的對象的引用,就可能導(dǎo)致內(nèi)存泄漏。如果集合是靜態(tài)的,那么該集合的生命周期就和程序的生命周期一致。且對象存放在靜態(tài)集合中,所以在整個程序的生命周期內(nèi),對象都無法被釋放,最終導(dǎo)致內(nèi)存泄漏。
2.連接未關(guān)閉
數(shù)據(jù)庫連接,網(wǎng)絡(luò)連接,IO連接等生成連接后,如果沒有調(diào)用close方法,則會造成相關(guān)的對象無法被回收,導(dǎo)致內(nèi)存泄漏。
3.單例對象
單例對象的生命周期和程序的生命周期也是一致的,所以如果單例對象引用了一個外部對象,那么這個外部對象在程序結(jié)束前也是無法被釋放的。存在內(nèi)存泄漏的風(fēng)險。
4.改變對象HASH值
如果一個對象被存入HashSet集合,再修改對象參與Hash值計算的屬性,那么對象的Hash值就會改變。由于對象存入HashSet集合時存放的位置是根據(jù)舊Hash值獲得的,那么當(dāng)Hash變動后,已經(jīng)找不回原來的位置,這就導(dǎo)致這個對象無法在HashSet被搜索到,也無法被刪除。由于一直存在于HashSet,那么除非HashSet被釋放,否則該對象將一直被HashSet引用,從而無法被釋放,造成內(nèi)存泄漏。
5.內(nèi)部類持有外部類引用
如果一個內(nèi)部類調(diào)用了一個外部類的方法,并且將內(nèi)部類作為參數(shù)傳遞過去。那么如果外部類不釋放這個內(nèi)部類,這個內(nèi)部類就無法釋放,就可能造成內(nèi)存泄漏。
排查步驟
1.通過jps命令找出正在執(zhí)行的虛擬機(jī)進(jìn)程,獲取進(jìn)程的在虛擬機(jī)中的唯一ID,命令格式如下:
Jps [options] [hostid]
例如 jps -l,結(jié)果如下:
options的參數(shù)如下:
-q | 不輸出類名、Jar名和傳入main方法的參數(shù) |
-m | 輸出傳入main方法的參數(shù) |
-l | 輸出main類或Jar的權(quán)限名 |
-v | 輸出傳入JVM的參數(shù) |
hostid可以用來查看其他服務(wù)器上虛擬器的進(jìn)程,默認(rèn)是本機(jī)
2.獲取唯一ID,可以使用jstat監(jiān)視進(jìn)程狀態(tài),命令格式如下:
Jstat [option vmid [interval[s|ms] [count]]]
例如 jstat -gc 12116 1000 4
每隔1000毫秒查詢某個進(jìn)程的已使用空間占總空間百分比,總共查4次,結(jié)果如下
S0C | 生存區(qū)0容量 |
S1C | 生存區(qū)1容量 |
S0U | 生存區(qū)0使用量 |
S1U | 生存區(qū)1使用量 |
EC | Eden區(qū)容量 |
EU | Eden區(qū)使用量 |
OC | 老年代容量 |
OU | 老年代使用量 |
MC | 方法區(qū)容量 |
MU | 方法區(qū)使用量 |
CCSC | 壓縮類空間容量 |
CCSU | 壓縮類空間使用量 |
YGC | 年輕代GC次數(shù) |
YGCT | 年輕代GC耗時 |
FGC | FULL GC 次數(shù) |
FGCT | FULL GC 耗時 |
GCT | GC總耗時 |
option的參數(shù)如下
-class | 顯示加載class的數(shù)量,及所占空間等信息 |
-compiler | 顯示VM實時編譯的數(shù)量等信息 |
-gc | 可以顯示gc的信息,查看gc的次數(shù),及時間 |
-gccapacity | 可以顯示VM內(nèi)存中三代(young,old,perm)對象的使用和占用大小 |
-gcutil | 統(tǒng)計gc信息 |
-gcnew | 年輕代對象的信息 |
-gcnewcapacity | 年輕代對象的信息及占用量 |
-gcold | old代對象的信息 |
-gcoldcapacity | old代對象的信息及占用量 |
-gcpermcapacity | perm對象的信息及占用量 |
-printcompilation | 當(dāng)前VM執(zhí)行的信息 |
3.可以使用jmap分析堆內(nèi)存使用情況,命令格式如下:
jmap [option] pid
例如:jmap -histo:live 6088,結(jié)果如下
沒有參數(shù)打印進(jìn)程的類加載器和類加載器加載的持久代對象
option的參數(shù)如下
-heap | 查看進(jìn)程堆內(nèi)存使用情況,包括使用的GC算法、堆參數(shù)配置和各代中堆內(nèi)存的使用情況 |
-histo | 查看堆內(nèi)存中的對象數(shù)目、大小統(tǒng)計 |
-histo:live | 查看堆內(nèi)存中活的對象數(shù)目、大小統(tǒng)計,并進(jìn)行一次GC |
-dump:format=b,file=dumpFileName | 用jmap把進(jìn)程內(nèi)存使用情況dump到文件中 |
通過檢查類的占用情況可以分析是哪個類出現(xiàn)了內(nèi)存泄漏,實在不行,也可以通過dump命令生成dump文件進(jìn)一步分析。
例如
jmap -dump:format=b,file=20210512.dump 6088
然后使用jvisualvm工具分析dump文件
關(guān)于JAVA中怎么排查內(nèi)存泄漏就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。