聊聊怎么排查堆內(nèi)存溢出
你知道的越多,你不知道的越多
上次給老公們說過了死循環(huán)cpu飆高的排查過程,今天就帶著老公們看看堆內(nèi)存溢出我們一般怎么排查的。
- cpu100%排查文章
在排查之前,我想jvm的基礎(chǔ)知識大家應(yīng)該都是了解了的吧?
老婆我就是不了解,人家要你說給我聽。
行行行,誒真實(shí)拿你們沒辦法,那我就帶大家回溫一下JVM的內(nèi)存模型(這玩意跟JAVA內(nèi)存模型JMM可不一樣,不要記錯(cuò)了)
今天我就直說堆,因?yàn)橐绯鍪前l(fā)送在堆中的。
JVM堆內(nèi)存被分為兩部分:年輕代(Young Generation)和老年代(Old Generation)。
年輕代年輕代是所有新對象產(chǎn)生的地方。當(dāng)年輕代內(nèi)存空間被用完時(shí),就會觸發(fā)垃圾回收。這個(gè)垃圾回收叫做Minor GC。
年輕代
被分為3個(gè)部分——Enden區(qū)和兩個(gè)Survivor區(qū)。
年輕代空間的要點(diǎn):
- 大多數(shù)新建的對象都位于Eden區(qū)。
- 當(dāng)Eden區(qū)被對象填滿時(shí),就會執(zhí)行Minor GC,并把所有存活下來的對象轉(zhuǎn)移到其中一個(gè)survivor區(qū)。
- Minor GC同樣會檢查存活下來的對象,并把它們轉(zhuǎn)移到另一個(gè)survivor區(qū)。這樣在一段時(shí)間內(nèi),總會有一個(gè)空的survivor區(qū)。
- 經(jīng)過多次GC周期后,仍然存活下來的對象會被轉(zhuǎn)移到年老代內(nèi)存空間,通常這是在年輕代有資格提升到年老代前通過設(shè)定年齡閾值來完成的。
年老代
年老代內(nèi)存里包含了長期存活的對象和經(jīng)過多次Minor GC后依然存活下來的對象,通常會在老年代內(nèi)存被占滿時(shí)進(jìn)行垃圾回收。
GC種類
Major GC
老年代的垃圾收集叫做Major GC,Major GC通常是跟full GC是等價(jià)的,收集整個(gè)GC堆。
分代GC
- Young GC:只收集年輕代的GC
- Old GC:只收集年老代的GC(只有CMS的concurrent collection是這個(gè)模式)
- Mixed GC:收集整個(gè)young gen以及部分old gen的GC(只有G1有這個(gè)模式)
Full GC
Full GC定義是相對明確的,就是針對整個(gè)新生代、老生代、元空間(metaspace,java8以上版本取代perm gen)的全局范圍的GC。
老公們可以從上圖看到年輕代分為了一個(gè)Eden區(qū)和兩個(gè)survivor區(qū)(S1,S2),survivor區(qū)同一時(shí)間只會有一個(gè)滿一個(gè)空,交替的。
然后就是GC到一定的閾值到老年代,今天不講永久代所以忽略Mataspace。
老婆:那怎么分析呢?
今天我就用一個(gè)JDK自帶的工具jvisualvm來給大家演示一波怎么操作的,因?yàn)檫@玩意誰都有,你去命令行敲一下jvisualvm就出來了(Mac是這樣的,不知道Windows是怎么樣子的)。
操作界面:
一般什么情況可能是出現(xiàn)了溢出呢?
超時(shí),不進(jìn)行服務(wù),服務(wù)掛掉,接口不在服務(wù)這樣的異常問題。
那模擬也很簡單,我寫個(gè)循環(huán)一直往List丟數(shù)據(jù),不使用list就能看到現(xiàn)象了
老公們可以看到圖形化界面還是很清晰明了的,這個(gè)是Visual GC的插件
大家點(diǎn)擊菜單欄的插件,然后安裝就好了,安裝完了記得點(diǎn)擊激活。
可以看到不釋放,堆空間就一直上去,直到OOM(out of memory)
這個(gè)時(shí)候我們就dump下來堆信息看看
會dump出一個(gè)這樣的hprof快照文件,可以用jvisualvm本身的系統(tǒng)去分析,我這里推薦MAT吧,因?yàn)槲伊?xí)慣這個(gè)了。
MAT :下載地址
下來好了我們可以看到mat已經(jīng)分析了我們的文件
你看他就是個(gè)暖男,都幫我們分析出來了一個(gè)問題,我們點(diǎn)進(jìn)去看看
他發(fā)現(xiàn)了是ArrayList的問題了,我們再往下看看
看到了嘛,具體代碼的位置都幫我們定位好了,那排查也就是手到擒來的事情了。
延伸點(diǎn)
上面我們使用工具jump了,那怎么去服務(wù)器上jump呢?
- jmap -dump:format=b,file=<dumpfile.hprof> <pid>
有老公可能問了,不是所有的故障當(dāng)時(shí)我們都在場的,無法及時(shí)jump,那也簡單
- -XX:+HeapDumpOnOutOfMemoryError
配置這玩意之后,oom的時(shí)候會自動jump的,到時(shí)候拿快照分析一波就好了。
MAT的功能還有很多的,百度谷歌太多工具文了,我就不做重復(fù)的工作了,比如還可以排查對象的強(qiáng)弱引用,還可以查看引用鏈等等。
還有個(gè)只寫這么點(diǎn)的原因是有點(diǎn)晚了,頂不住了,最近不拍視頻也是因?yàn)槭虑槎嗔?,有點(diǎn)小忙,希望老公們體量,對了Redis的分布式鎖已經(jīng)在安排的路上了。
我是敖丙,一個(gè)在互聯(lián)網(wǎng)茍且偷生的工具人。