目錄
- 1 自動記憶體管理
- 2 物件優先在Eden分配
- 2.1 總結
- 2.2 驗證程序
- 3 大物件直接進入老年代
- 3.1 總結
- 3.2 驗證程序
- 4 長期存活的物件將進入老年代
- 4.1 總結
- 4.2 驗證程序
- 5 動態物件年齡判定
- 5.1 總結
- 5.2 驗證程序
- 6 空間分配擔保
- 6.1 總結
- 6.2 驗證程序
擴展:Gc日志分析工具
GC日志分析工具-GCEasy
GC日志分析神器-GCEasy詳解
1 自動記憶體管理
Java技術體系的自動記憶體管理,最根本的目標是自動化地解決兩個問題:分配與回收
- 自動給物件分配記憶體
- 自動回收分配給物件的記憶體
Java的物件記憶體分配的一般規則:
- 一般情況下,給物件分配堆記憶體;即時編譯下,也會間接地分配堆疊記憶體
- 新生物件通常會分配在新生代中,少數情況下(例如物件大小超過一定閾值)也可能會直接分配在老年代,
- 《Java虛擬機規范》并未規定新物件的創建和存盤細節,這取決于虛擬機當前使用的是哪一種垃圾收集器,以及虛擬機中與記憶體相關的引數的設定,
本章節所以用的JVM環境為:
JDK8默認:
垃圾收集器:
新生代使用 Parallel Scavenge:標記-復制演算法
老年代配合使用的是 Serial Old:標記-整理演算法
2 物件優先在Eden分配
2.1 總結
- 新生代分為一個Eden區和兩個survivor區,默認比例為是 8:1:1,(設定引數-XX:-UseAdaptiveSizePolicy可固定該比例)
- 物件優先被分配在eden區,eden區滿了后會觸發minor gc,把剩余存活的物件挪到為空的那塊survivor區,下一次eden區滿了后又會觸發minor gc,把eden區和survivor區垃圾物件回收,把剩余存活的物件一次性挪動到另外一塊為空的survivor區,
- 如果survivor區空間不足,通過擔保機制挪動到老年代,
2.2 驗證程序
jvm引數:
-Xms30M -Xmx30M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:-UseAdaptiveSizePolicy -XX:+PrintCommandLineFlags -XX:+PrintGCDateStamps
-Xms30M #固定堆記憶體大小為30M
-Xmx30M
-Xmn10M #新生代為分配10M,實際可用為9M
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:-UseAdaptiveSizePolicy #固定8:1:1
-XX:+PrintCommandLineFlags #列印運行時jvm引數
-XX:+PrintGCDateStamps
特別注意:
未手動分配空間前,運行main方法占用:1476KB,即1.44MB

測驗代碼:
public class GcDemo {
public static void main(String[] args) {
byte[] a1 = new byte[5 * 1024 * 1024];
byte[] a2 = new byte[2 * 1024 * 1024];
}
}
GC日志及分析:

-
[GC (Allocation Failure) :收集型別是:Minor GC (GC代表MinorGC,System.gc()代表Full GC)
-
[PSYoungGen: 6432K->640K(9216K)] 翻譯為 [新生代:新生代收集前記憶體使用量->新生代垃圾收集后記憶體使用量(新生代代可用記憶體總大小)],垃圾收集前新生代已使用 6432K(6.28M),垃圾收集后已使用640K,總可用大小為 9216K(9M) ,
- 6.28M:初始占用的1.44m+a1先被分配在eden區
- a2分配時,eden剩余空間不足,觸發MinorGC,此時有1476K-640K被回收,a1仍被使用,不被回收,
- 9216K,MinorGC后,總共可用記憶體為eden+1個survivor區
-
MinorGC后記憶體占用情況:
PSYoungGen total 9216K, used 2770K #新生代已使用2770K包含:物件a2+剩余未回收的640K
eden space 8192K, 26% used # eden區總大小8192K,已使用26%,包含物件a2
from space 1024K, 62% used #S0總大小1024K,已使用62%,包含 剩余未回收的640K
to space 1024K, 0% used #S1總大小1024K,已使用0%
ParOldGen total 20480K, used 5128K #物件a1被搬移到老年代
object space 20480K, 25%
綜上:
- 未分配任何物件時,系統默認占用了1476KB
- 創建a1時,a1被分配在eden區
- 創建a2時,eden區剩余空間不足,觸發MinorGC,同時survivor空間不足以存放a1,所以通過分配擔保機制將a1提前轉移到老年代去,同時將回收了一部分默認占用的1476K,未被回收的640K存放在其中一個survivor
用圖例所示:

3 大物件直接進入老年代
3.1 總結
- 在Java虛擬機中要避免大物件的原因是,在分配空間時,它容易導致記憶體明明還有不少空間時就提前觸發垃圾收集,以獲取足夠的連續空間才能安置好它們,而當復 制物件時,大物件就意味著高額的記憶體復制開銷,
- HotSpot虛擬機提供了-XX:PretenureSizeThreshold 引數,指定大于該設定值的物件直接在老年代分配,這樣做的目的就是避免在Eden區及兩個Survivor區 之間來回復制,產生大量的記憶體復制操作,
3.2 驗證程序
如上:并未觸發gc,而是直接分配在老年代
4 長期存活的物件將進入老年代
4.1 總結
- 虛擬機給每個物件定義了一個對 象年齡(Age)計數器,存盤在物件頭中
- 物件通常在Eden區里誕生,如果經過第一次 Minor GC后仍然存活,并且能被Survivor容納的話,該物件會被移動到Survivor空間中,并且將其物件 年齡設為1歲
- 物件在Survivor區中每熬過一次Minor GC,年齡就增加1歲,當它的年齡增加到一定程 度(默認為15),就會被晉升到老年代中,
- 可以通過引數-XX: MaxTenuringThreshold 設定“年齡”最大值
4.2 驗證程序
todo
5 動態物件年齡判定
5.1 總結
- HotSpot虛擬機并不是永遠要求物件的年齡必須達到- XX:MaxTenuringThreshold才能晉升老年代
- 如果在Survivor空間中相同年齡所有物件大小的總和大于 Survivor空間的一半,年齡大于或等于該年齡的物件就可以直接進入老年代,無須等到-XX: MaxTenuringThreshold中要求的年齡,
5.2 驗證程序
todo
6 空間分配擔保
6.1 總結
- 在發生Minor GC之前,虛擬機必須先檢查老年代最大可用的連續空間是否大于新生代所有物件總空間,如果這個條件成立,那這一次Minor GC可以確保是安全的
- 如果不成立,則虛擬機會先查看- XX:HandlePromotionFailure引數的設定值是否允許擔保失敗;如果允許,那會繼續檢查老年代最大可用的連續空間是否大于歷次晉升到老年代物件的平均大小,如果大于,將嘗試進行一次Minor GC;盡管這次Minor GC是有風險的;如果小于,或者-XX: HandlePromotionFailure設定不允許冒險,那這時就要改為進行一次Full GC,
6.2 驗證程序
todo
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/516292.html
標籤:Java
下一篇:SSM框架整合
