jvm內存管理-堆內存分配

jvm內存管理

在整個java技術體系中,自動內存管理簡單說來就是解決兩個問題:給對象分配內存和回收分給對象的內存。關於回收內存,上篇博客已經介紹了—>java垃圾收集。接下來說說關於給對象分配內存的問題。對象的內存分配,往大方向說就是在堆上分配,分配規則根據不同的垃圾收集器組合也不盡相同,下面記錄了幾條最普遍的分配規則。

1. 對象優先在Eden分配

多數情況下,對象在新生代Eden區中分配,當該區沒有足夠空間進行分配時,虛擬機會發起一次Minor GC。說到這,解釋下Minor GC和Major GC:

Minor GC指發生在新生區的垃圾收集行爲,Minor GC特點是非常頻繁,回收速度較快
Major GC 也叫Full GC,指發生在老年代的GC。特點和Minor GC相反,回收頻率低,速度慢

2. 大對象直接進入老年代

大對象是指需要大量連續內存空間的java對象,例如很長的字符串或數組。我們寫程序的時候儘量避免寫出“短命的大對象”,這會導致在還有內存的情況下虛擬機提前進行垃圾收集來騰出空間安置大對象。
虛擬機提供了一個參數-XX:PretenureSizeThreshold,大於該值的對象將直接分配到老年代,這樣做避免了在Eden區和Survivor區之間發生大量內存複製(上篇已經提到新生代使用複製算法)。

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

關於老年代和年輕代,虛擬機爲了實現分代收集的思想,給每個對象定義了一個年齡(Age)計數器。對象在Eden出生經過第一次Minor GC後存活並且被移動到了Survivor區,對象年齡即爲1,以後每當該對象在Survivor區熬過一次Minor GC,年齡就會加一。當它的年齡增加到一定程度後,就會進入老年代。這個閾值可以通過參數-XX:MaxTenuringThreshold設置,默認爲15。

4. 動態對象年齡判定

爲了更好的適應不同程序內存特點,虛擬機並非永遠要求對象年齡達到MaxTenuringThreshold才能晉升老年代。如果在Survivor空間中相同年齡的所有對象總和大於Survivor空間的一半,年齡大於或等於該年齡的對象直接進入老年代。

5. 空間分配擔保機制

當一個對象要進入新生代時,Survivor區空間如果不夠當前存活的對象全部複製的話,需要老年代進行分配擔保。在Minor GC之前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代對象總空間,如果大於,那麼Minor GC是安全的;如果不大於,虛擬機會查看HandlePromotionFailure設置是否允許擔保失敗,如果允許,繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代對象的平均大小,如果大於則進行Minor GC(有一定風險),如果小於則進行一次Full GC(Major GC);如果HandlePromotionFailure設置不允許擔保失敗且老年代最大可用的連續空間小於新生代對象總空間,也要進行一次Full GC。關於上面所說的風險,這裏說明一下:

因爲新生代使用複製算法,爲了提高內存利用率,每次只使用其中一個Survivor區作爲輪換備份,當出現大量對象在Minor GC後仍然存活,一般是指大於10%的對象存活,極端情況下所有對象都存活。Survivor區無法容納這麼多對象,這時候老年代需要提供空間擔保,前提是老年代有足夠的空間進行擔保。根據歷次新晉老年代對象平均值是一種概率事件,自然存在“風險”。

本篇介紹了Java虛擬機自動內存分配的主要規則。參考《深入理解java虛擬機》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章