前言
我們在Java面試中,只要是2年以上經(jīng)驗,一定會問你一下關(guān)于JVM方面的問題。開發(fā)兩年時間不能對JVM沒有了解,如果你還不了解,說明你的學習與探索能力不高,不能給到應有的加分項哦!小編也是最近剛剛開始學習,總結(jié)一下最近的學習成果。方便以后看,也希望小伙伴們看到可以幫助到您!
JVM堆內(nèi)存結(jié)構(gòu)簡述
JVM堆內(nèi)存結(jié)構(gòu)圖
堆初體驗
所有的對象實例以及數(shù)組都要在堆上分配,堆是垃圾收集器管理的主要區(qū)域,也被稱為“GC 堆
”,也是我們優(yōu)化最多考慮的地方。因為在一個項目中,會不斷地創(chuàng)建對象,都是在堆里創(chuàng)建,如果一直不回收就會導致OOM
,我們聽的最多的情況哈!還有經(jīng)常說的JVM調(diào)優(yōu)
,也是對堆
進行參數(shù)優(yōu)化配置,達到最接近理想狀態(tài)。
結(jié)構(gòu)詳情
新生代
大部分剛創(chuàng)建的對象首先都是放在年輕代,新生代內(nèi)存按照 8:1:1 的比例分為一個
Eden 和兩個 Survivor
(Survivor from,Survivor to)。
1. Eden 空間
Eden空間:主要是存放剛剛創(chuàng)建的新對象,如果可以Eden空間充足,新對象直接存放在Eden中,如果對象過大,放不下則會觸發(fā)
Minor GC(效率很快)
。
2. Survivor 空間
每次執(zhí)行Minor GC,會將Eden區(qū)中存活的對象放到Survivor的From區(qū),而在From區(qū)中,仍存活的對象會根據(jù)他們的年齡值來決定去向,逃過一次Minor GC年齡
加1
,默認年數(shù)為15
,就要到老年區(qū)
。(From Survivor和To Survivor的邏輯關(guān)系會在GC時發(fā)生顛倒
: From變To , To變From,目的是保證有連續(xù)的空間存放對方,避免碎片化的發(fā)生,后面GC流程在詳細說)
老年代
在新生代中經(jīng)歷了 N 次(
默認15次
)垃圾回收后仍然存活的對象,就會被放到年老代中。年老代中存放的都是一些生命周期較長的對象。當老年代內(nèi)存滿時觸發(fā)Major GC 即 Full GC
,F(xiàn)ull GC 發(fā)生頻率比較低
,執(zhí)行時間也是Minor GC的十倍以上
。在老年代的對象一般為:存活時間比較長的,還有就是比較大的對象。
永久代/元空間
Java8 以前永久代,受JVM 管理,java8 以后元空間,直接使用物理內(nèi)存。
元空間位于堆外
,所以它的最大內(nèi)存大小取決于系統(tǒng)內(nèi)存,而不是堆大小,我們可以指定MaxMetaspaceSize
參數(shù)來限定它的最大內(nèi)存。
GC回收流程
GC回收流程圖
GC回收詳細流程
當一個新對象創(chuàng)建時,首先會來到新生區(qū)的Eden區(qū)中,這里進行第一次判斷:判斷當前新對象是否可以再Eden區(qū)放得下,如果放下我們直接放到Eden區(qū)分配內(nèi)存即可;如果放不下時,就要進行一次Minor GC。此次GC我們展開來詳細說一下:回收時進行第二次判斷:判斷Survivor0是否放得下,如果放得下Eden 區(qū)存活對象復制到一個 Survivor0 區(qū),然后清空 Eden 區(qū),當這個 Survivor0 區(qū)也存放滿了時,則將 Eden 區(qū)和 Survivor0 區(qū)存活對象復制到另一個 Survivor1 區(qū),然后清空 Eden 和這個 Survivor0 區(qū),此時 Survivor0 區(qū)是空的,然后將 Survivor0 區(qū)和 Survivor1 區(qū)交換,即保持 Survivor1 區(qū)為空, 如此往復(對照上面兩個區(qū)域來回切換)。當對象在 Survivor 區(qū)躲過一次 GC 的話,其對象年齡便會加 1,此時進行第三次判斷:判斷年齡是否達到閾值,默認情況下,如果對象年齡達到 15 歲。超過就會移動到老年代中。不超則繼續(xù)在Survivor。(對照上圖虛線框)
執(zhí)行完Minor GC后,進行第四次判斷:判斷Eden區(qū)是否放得下,如果放得下就進行內(nèi)存分配,如果放不下默認作為大對象放到老年區(qū)。此時進行第五次判斷新對象是否在老年區(qū)放得下,如果放得下就進行內(nèi)存分配;如果放不下則進行一次Major GC 即 Full GC(執(zhí)行時間為Minor GC的10倍多),最后進行第五次判斷:判斷老年區(qū)是否放得下,如果放得下進行內(nèi)存分配;放不下則直接報異常OOM,此時需要改變堆的內(nèi)存大小了。
-Xmx:最大堆大小
-Xms:初始堆大小
查看JDK自帶可視化堆空間圖
1. Win + R 輸入jvisualvm
2. 安裝GC插件
JVM監(jiān)控工具jvisualvm的使用及GC插件安裝
3. 查看內(nèi)存圖
總結(jié)
這樣一個大的面試題就描述完成了,主要是理解GC回收的流程懂了,堆的結(jié)構(gòu)也就知道怎么回事了。