
JVM 復(fù)盤
一 JVM內(nèi)存塊結(jié)構(gòu)
主要是堆棧;方法區(qū);而我們關(guān)注比較多的是堆區(qū)域,而方法區(qū)存放的信息比較少很少會(huì)有內(nèi)存溢出的情況(JDK8 元空間后更加沒有)。堆區(qū)域分為新生代的Eden/S0/S1區(qū)域、老年代分為:Old區(qū)域;對(duì)象會(huì)先到Eden/S0區(qū)域,當(dāng)Eden/S0區(qū)域滿了;會(huì)觸發(fā)YGC會(huì)標(biāo)記的對(duì)象歲數(shù);并壓到S1區(qū)域。
-
當(dāng)S1區(qū)域滿了、或者對(duì)象標(biāo)記15次;就會(huì)把存活的對(duì)象放到Old老年代;當(dāng)老年代滿了觸發(fā)Full GC這時(shí)候會(huì)把新生代、老年代全部GC一遍。這個(gè)時(shí)候會(huì)觸發(fā)STW問題,分代的設(shè)計(jì)主要是最大努力避免對(duì)象到Old并觸發(fā)Full GC 造成STW問題。
image.png
二、垃圾收集器cms/g1之間的區(qū)別
CMS
本質(zhì)上就是說在CMS GC期間,他需要把用戶線程都停下來;對(duì)內(nèi)存對(duì)象進(jìn)行標(biāo)記清理在我們系統(tǒng)使用CMS一般優(yōu)化就是內(nèi)存不夠用就調(diào)大一些、在極端業(yè)務(wù)場(chǎng)景的情況下;可能會(huì)根據(jù)業(yè)務(wù)場(chǎng)景來設(shè)置堆大小,比如調(diào)??;觸發(fā)gc的耗時(shí)(RT)降低了;但是GC的頻率會(huì)提高高;調(diào)大了觸發(fā)GC頻率降低了、但每次觸發(fā)的耗時(shí)(RT) 也提高了。
但一般業(yè)務(wù)場(chǎng)景是可以接受GC造成的停頓耗時(shí);所以會(huì)在宿主機(jī)內(nèi)存可用的情況下還是去調(diào)大內(nèi)存,如果調(diào)小的話;對(duì)象回收不了也很容易造成內(nèi)存溢出、風(fēng)險(xiǎn)更大。
G1
- G1 邏輯上區(qū)域還是一樣的。新生代(包含三個(gè)區(qū)域(Eden/S0/S1區(qū)域)、老年代(old)但是他的結(jié)構(gòu)發(fā)生了巨大的變化;就是說他把內(nèi)存分為2048個(gè)內(nèi)存塊;每個(gè)塊的大小在[1M,32M]之間。
- 分成塊的主要目的是可以控制掃描范圍、這是G1核心功能;我們是可以設(shè)置每次GC的最大毫秒數(shù)、G1會(huì)根據(jù)我們?cè)O(shè)置的毫秒數(shù)來決定每次去回收多少個(gè)region塊。
- G1的優(yōu)點(diǎn)就是更靈活了、GC耗時(shí)可配置;最大可能降低了掃描范圍,雖然也有STW問題;但是他先圈了一塊region再去回收(有限使用比較多的region區(qū)域)。更精細(xì)、延遲更低了,也沒有垃圾碎片的問題;不像CMS那樣每次還要STW整個(gè)堆區(qū)域;還有垃圾碎片的問題。
-
但是G1 GC的頻率更高了。對(duì)CPU使用也比較頻繁;因?yàn)槊看蜧C的區(qū)域比較小。CMS GC耗時(shí)不可預(yù)測(cè)、CPU使用率低、在能夠容忍GC STW還是不錯(cuò)的選擇,還有就是G1的新版對(duì)STW的優(yōu)化可能要收費(fèi)。
image.png
三、jdk7/jdk8之間的區(qū)別
- 永久代 JDK7 存儲(chǔ)的信息比較少、方法、常量等;基本不會(huì)觸發(fā)Full GC、JDK8使用了元空間后;實(shí)際上默認(rèn)共享了物理內(nèi)存、也就是說物理內(nèi)存有多大;就可以使用多大;充分降低了JVM可能會(huì)造成的GC影響;但一般都會(huì)去設(shè)置元空間大小為了避免對(duì)宿主機(jī)內(nèi)存造成影響;影響其他進(jìn)程。
四、排查高耗GC的方式
- 通過top 看高耗線程、線程ID 轉(zhuǎn)換16進(jìn)制 、再通過jstack 打印堆棧信息、找到16進(jìn)制的代碼塊。
- 通過jmap gcutil 查看內(nèi)存分配、內(nèi)存實(shí)時(shí)運(yùn)行狀態(tài) 來判斷。很多時(shí)候內(nèi)存溢出都會(huì)觸發(fā)大量的Full GC通過gcutils 可以找到判斷信息。有些情況并沒有代碼拋異常、就是觸發(fā)Full GC 導(dǎo)致系統(tǒng)卡頓、這個(gè)時(shí)候查詢JVM內(nèi)存狀態(tài)是非常好的手段。

