前言
我們在Java面試中,只要是2年以上經驗,一定會問你一下關於JVM方面的問題。開發兩年時間不能對JVM沒有了解,如果你還不瞭解,說明你的學習與探索能力不高,不能給到應有的加分項哦!小編也是最近剛剛開始學習,總結一下最近的學習成果。方便以後看,也希望小夥伴們看到可以幫助到您!
JVM堆記憶體結構簡述
JVM堆記憶體結構圖
堆初體驗
所有的物件例項以及陣列都要在堆上分配,堆是垃圾收集器管理的主要區域,也被稱為“GC 堆
”,也是我們優化最多考慮的地方。因為在一個專案中,會不斷地建立物件,都是在堆裡建立,如果一直不回收就會導致OOM
,我們聽的最多的情況哈!還有經常說的JVM調優
,也是對堆
進行引數優化配置,達到最接近理想狀態。
結構詳情
新生代
大部分剛建立的物件首先都是放在年輕代,新生代記憶體按照 8:1:1 的比例分為一個
Eden 和兩個 Survivor
(Survivor from,Survivor to)。
1. Eden 空間
Eden空間:主要是存放剛剛建立的新物件,如果可以Eden空間充足,新物件直接存放在Eden中,如果物件過大,放不下則會觸發
Minor GC(效率很快)
。
2. Survivor 空間
每次執行Minor GC,會將Eden區中存活的物件放到Survivor的From區,而在From區中,仍存活的物件會根據他們的年齡值來決定去向,逃過一次Minor GC年齡
加1
,預設年數為15
,就要到老年區
。(From Survivor和To Survivor的邏輯關係會在GC時發生顛倒
: From變To , To變From,目的是保證有連續的空間存放對方,避免碎片化的發生,後面GC流程在詳細說)
老年代
在新生代中經歷了 N 次(
預設15次
)垃圾回收後仍然存活的物件,就會被放到年老代中。年老代中存放的都是一些生命週期較長的物件。當老年代記憶體滿時觸發Major GC 即 Full GC
,Full GC 發生頻率比較低
,執行時間也是Minor GC的十倍以上
。在老年代的物件一般為:存活時間比較長的,還有就是比較大的物件。
永久代/元空間
Java8 以前永久代,受JVM 管理,java8 以後元空間,直接使用實體記憶體。
元空間位於堆外
,所以它的最大記憶體大小取決於系統記憶體,而不是堆大小,我們可以指定MaxMetaspaceSize
引數來限定它的最大記憶體。
GC回收流程
GC回收流程圖
GC回收詳細流程
當一個新物件建立時,首先會來到新生區的Eden區中,這裡進行
第一次判斷
:判斷當前新物件是否可以再Eden區放得下,如果放下我們直接放到Eden區分配記憶體即可;如果放不下時,就要進行一次Minor GC
。此次GC我們展開來詳細說一下:回收時進行第二次判斷
:判斷Survivor0是否放得下,如果放得下Eden 區存活物件複製到一個 Survivor0 區,然後清空 Eden 區,當這個 Survivor0 區也存放滿了時,則將 Eden 區和 Survivor0 區存活物件複製到另一個 Survivor1 區,然後清空 Eden 和這個 Survivor0 區,此時 Survivor0 區是空的,然後將 Survivor0 區和 Survivor1 區交換,即保持 Survivor1 區為空, 如此往復(對照上面兩個區域來回切換)。當物件在 Survivor 區躲過一次 GC 的話,其物件年齡便會加 1,此時進行第三次判斷
:判斷年齡是否達到閾值,預設情況下,如果物件年齡達到 15 歲。超過就會移動到老年代中。不超則繼續在Survivor。(對照上圖虛線框)
執行完Minor GC
後,進行第四次判斷
:判斷Eden區是否放得下,如果放得下就進行記憶體分配,如果放不下預設作為大物件放到老年區
。此時進行第五次判斷
新物件是否在老年區放得下,如果放得下就進行記憶體分配;如果放不下則進行一次Major GC 即 Full GC(執行時間為Minor GC的10倍多)
,最後進行第五次判斷
:判斷老年區是否放得下,如果放得下進行記憶體分配;放不下則直接報異常OOM
,此時需要改變堆的記憶體大小了。
-Xmx:最大堆大小
-Xms:初始堆大小
檢視JDK自帶視覺化堆空間圖
1. Win + R 輸入jvisualvm
2. 安裝GC外掛
3. 檢視記憶體圖
總結
這樣一個大的面試題就描述完成了,主要是理解GC回收的流程懂了,堆的結構也就知道怎麼回事了。
參考文章: 文章地址
隨便推廣一下自己的網站!!!