【面試必備】小夥伴栽在了JVM的內存分配策略。。。

週末有小夥伴留言說上週面試時被問到內存分配策略的問題,但回答的不夠理想,小夥伴說以前公號裏看過這一塊的文章的,當時看時很清楚,也知道各個策略是幹嗎的,但面試時腦子裏清楚,內心很明白,但嘴裏就是說不清楚,說出來的就是像雲像霧又像風,最後面試官說他應該是不清楚這一塊的內容面試

這裏給小夥伴要再次說明下,任何知識點,先抓主幹,再摸細節。對於面試來講,能把各個主幹捋清楚,只要面試官要求不是過高,都是能過關的。畢竟jvm參數那麼多,難不成面試官揪着各個參數的做用不放?若是真遇到這種太過揪細節的,只能說江湖路遠,有緣再見!算法

對象的內存分配,往大方向上講,就是在上分配(但也可能通過JIT編譯後被拆散爲標量類型並間接地棧上分配),對象主要分配在新生代的Eden區上,若是啓動了本地線程分配緩衝,將按線程優先在TLAB上分配。少數狀況下可能會直接分配在老年代中。數組

對象優先在Eden分配

大多數狀況下,對象在新生代Eden區中分配。當Eden區沒有足夠空間進行分配時,虛擬機將發起一次Minor GC(前面篇章中有介紹過Minor GC)。但也有一種狀況,在內存擔保機制下,沒法安置的對象會直接進到老年代。安全

大對象直接進入老年代

大對象時指須要大量連續內存空間的Java對象,最典型的大對象就是那種很長的字符串以及數組。jvm

虛擬機提供了一個-XX:PretenureSizeThreshold參數,令大於這個設置值的對象直接在老年代分配。目的就是避免在Eden區及兩個Survivor區之間發生大量的內存複製。線程

長期存活的對象將進入老年代

虛擬機給每一個對象定義了一個對象年齡(Age)計數器。若是對象在Eden出生並通過第一次Minor GC後仍然存活,而且能被Survivor容納的話,將被移動到Survivor空間中,而且對象年齡設爲1 。對象在Survivor區中沒通過一次Minor GC,年齡就加1歲,當年齡達到15歲(默認值),就會被晉升到老年代中。指針

對象晉升老年代的年齡閾值,能夠經過參數-XX:MaxTenuringThreshold設置。cdn

接下來咱們來回答JVM的分代年齡爲何是15?而不是16,20之類的呢?

真的不是爲何不能是其它數(除了15),着實是臣妾作不到啊!中間件

事情是這樣的,HotSpot虛擬機的對象頭其中一部分用於存儲對象自身的運行時數據,如哈希碼(HashCode)、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID、偏向時間戳等,這部分數據的長度在32位和64位的虛擬機(未開啓壓縮指針)中分別爲32bit和64bit,官方稱它爲「Mark word」。對象

例如,在32位的HotSpot虛擬機中,若是對象處於未被鎖定的狀態下,那麼Mark Word的32bit空間中25bit用於存儲對象哈希碼,4bit用於存儲對象分代年齡,2bit用於存儲鎖標誌位,1bit固定爲0 。

明白是什麼緣由了嗎?對象的分代年齡佔4位,也就是0000,最大值爲1111也就是最大爲15,而不可能爲16,20之類的了。

動態對象年齡斷定

爲了能更好的適應不一樣程序的內存情況,虛擬機並非永遠地要求兌現過的年齡必須達到了MaxTenuringThreshold才能晉升老年代。

知足以下條件之一,對象能晉升老年代:

  1. 對象的年齡達到了MaxTenuringThreshold(默認15)能晉升老年代。
  2. 若是在Survivor空間中相同年齡全部對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就能夠直接進入老年代,無須等到MaxTenuringThreshold中要求的年齡。

不少文章都只是注意到了上面描述的狀況(包括阿里中間件公衆號發的一篇文章裏也只是這麼簡單的介紹),但若是隻是這麼認識的話,會發如今實際的內存回收中有悖於此條規定。

舉個小栗子,如對象年齡5的佔34%,年齡6的佔36%,年齡7的佔30%,按那兩個標準,對象是不能進入老年代的,但Survivor都已經100%了啊?

你們能夠關注這個參數TargetSurvivorRatio,目標存活率,默認爲50%。大體意思就是說年齡從小到大累加,如加入某個年齡段(如栗子中的年齡6)後,總佔用超過Survivor空間TargetSurvivorRatio的時候,從該年齡段開始及大於的年齡對象就要進入老年代(即栗子中的年齡6,7對象)。動態對象年齡判斷,主要是被TargetSurvivorRatio這個參數來控制。並且算的是年齡從小到大的累加和,而不是某個年齡段對象的大小。

空間分配擔保

在發生Minor GC以前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代全部對象總空間,若是這個條件成立,那麼Minor GC能夠確保是安全的。若是不成立,則虛擬機會查看HandlePromotionFailure設置值是否容許擔保失敗。若是容許,那麼會繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代對象的平均大小,若是大於,將嘗試着進行一次Minor GC,儘管此次Minor GC是有風險的;若是小於,或者HandlePromotionFailure設置不容許冒險,那這時也要改成進行一次Full GC 。

上面說的風險是什麼呢?咱們知道,新生代使用複製收集算法,但爲了內存利用率,只使用其中一個Survivor空間來做爲輪換備份,所以當出現大量對象在Minor GC後仍然存活的狀況(最極端的狀況就是內存回收後新生代中全部對象都存活),就須要老年代進行分配擔保,把Survivor沒法容納的對象直接進入老年代。

總結腦圖file

備註: 腦圖太大,如需高清完整大圖,可在「猿人谷」公衆號後臺輸入:jvm

相關文章
相關標籤/搜索