JVM GC 之二對象分配

      Java體系中的內存自動管理其實是解決兩大問題:給對象分配內存和回收分配個對象的內存。
     一般情況下對象是在堆上分配(但也可能是經過JIT(Java即時編譯)編譯後被拆散爲標量類型並間接的在棧上分配),對象主要是分配在新生代中的Eden區,如果啓動了本地線程分配緩衝,將按線程優先分TLAB上。也可以通過配置 -XX:PretenureSizeThreshold參數直接分配在老年代中。

     英文詩意:Max  Tenuring佔有 Threshole閥值

     對象有限分配在Eden區
     多數情況下,對象在新生代Eden中分配,當Eden區內存不足時,進行一次Minor GC.(年輕代GC)

     可以配置 -XX:PrintGCDetails參數,告訴虛擬機在垃圾收集行爲發生時打印內存回收日誌,並且在進程退出的時候輸出當前內存各區域的分配情況。

     配置參數-Xms20M, -Xmx20M 和 -Xmn10M 設置Java堆大小爲20M,且不可擴展,同時設置新生代10M ,剩下10M分配給老年代。

     配置參數 -XX:SurvivorRatio=8 設置新生代中Eden區與一個Survivor空間大小是8:1.

     Minor GC : 新生代GC,發生在新生代的垃圾收集動作,因爲新生代中的對象都具備朝生夕死特性,所以Minor GC非常頻繁。

     Major GC/Full GC : 老年代GC,發生在老年代中的垃圾收集動作,一般發Full GC之前都會伴隨着至少一次的Minor GC. Full GC 會比Minor GC慢10倍以上。
     
     大對象直接進入老年代
     這裏所說的大對象是指需要大量連續內存空間的Java對象,比較典型的就是特別長的字符串及數組。經常出現大對象會導致內存還有很多空餘就提前觸發GC動作,以獲取足夠的連續空間。

     朝生夕滅的短命大對象會在新生代的Eden中分配,這類對象過多時會引起過多的GC操作:從Eden 、from Survivor 到 to Survivor 兩個區域間的複製操作。開發中應當避免生成這樣的對象。

     配置 -XX:PretenureSizeThreshold 參數使大於這個閥值的對象直接進入老年代中分配,從而避免在Eden和兩個Survivor區間的對象拷貝。備註:新生代中採用複製算法回收內存。 

     長期存活的對象將進入老年代
     虛擬機採用分代收集器的思想來管理內存,分代算法就是: 新生代中的對象都是朝生夕死,採用複製算法,Eden\From Survivor 到 To Survivor 區域中拷貝還活着的對象;老年代中的對象標記-清理和標記-整理算法回收,避免大量活着的大對象來回拷貝。

     那當對象從Eden 、From Survivor 區域中拷貝出去時,是怎麼決定對象要放入到 To Survivor中還是老年代中的呢?
     虛擬機給每個對象定義了一個年齡計算器,如果對象經歷過一次Minor GC後仍然存活並且能被 To Survivor收容的話,該對象將被移動到Survivor區域中,並把對象年齡設爲1。對象在Survivor中每熬過一次Minor GC,年齡就增加一歲,當他的年齡達到一定歲數時(默認15歲),就會晉升到老年代。
     
     配置參數 -XX:MaxTenuringThreshold=8 設置對象8歲時晉升到老年代區間。

     對象年齡動態判定
     如果Sruvivor區間中的所有相同年齡的對象的總和大於Survivor空間的一半,年齡 大於或等於該年齡的對象將直接進入老年代,無需等待 -XX:MaxTenuringThreshole設置的年齡。

     空間分配擔保
     發送Minor GC 時,虛擬機會檢測之前每次晉升到老年代的平均大小是否大於老年代的剩餘空間大小。如果大於,則改爲直接Full GC ; 如果小於,再查看 HandlePromotionFailure設置是否允許擔保失敗,如果允許,則會進行Minor GC,如果出現HandlePromotionFailure 失敗,就會在失敗後重新發起一次Full GC ; 如果不允許,則也要改爲進行一次Full GC .

     新生代採用複製算法回收內存,爲了內存利用率,只使用其中一個Survivor作爲輪換備份,因此當Survivor的空間不足以存儲MinorGC 存活下來的對象時,就需要老年代進行分配擔保。前提是老年代需要有足夠的空間進行存儲MinorGC存活下來的對象,一共有多少對象會活下來,在實際完成回收之前是無法明確知道的。所以只能取之前每一次回收晉升到老年代對象容量的平均大小值作爲經驗值,如果經驗值大於老年代的空間,則需要進行一次Full GC.

     既然是平均值,就會存在實際值大於老年代空間的情況,這時就會出現擔保失敗,如果出現了擔保失敗,就會在失敗後進行一次Full GC.

      雖然擔保失敗後再進行Full GC 是繞了一大圈子,但大部分還會把HandlPromotionFailure開關打開,防止Full GC過於頻繁。

     垃圾收集器
     Stop The World!當GC開始工作時,必須暫停其他線程。

     並行:多條垃圾收集線程並行工作,但此時用戶線程仍然是暫停的。
     併發:用戶線程和垃圾收集線程同時執行,但不一定是並行的,可能會交替執行。用戶線程繼續運行,而垃圾收集線程運行在另一個CPU上。

     






















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章