Java全面解讀垃圾回收機制
阿新 • • 發佈:2018-12-22
1. JVM垃圾回收機制與實現
- 堆:所有的物件例項與陣列,GC堆,分為新生代與老年代
- 棧:棧幀包含區域性變量表(基本資料型別 8種、物件引用型別)、運算元棧、動態連結、方法出口
- 方法區:類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料,也成為永久代
一般說棧指的是 虛擬機器棧,或者說是虛擬機器棧中的區域性變量表
TLAB:本地執行緒分配緩衝,執行緒分配記憶體,現用TLAB分配,用完重新分配新的TLAB
可以設定是否啟用TLAB
Mark Word:物件頭:物件自身的執行時資料,雜湊嗎,GC分代年齡,鎖狀態,持有的鎖,偏向執行緒ID,偏向時間戳
HotSpot採用直接指標訪問,棧中直接指向物件的地址,物件移動時,需要改變棧中的reference
2、垃圾回收演算法
- 標記清除演算法 Mark-sweep
存在效率問題與空間問題(產生大量不連續的記憶體碎片) - 複製演算法(Copying):應用十分廣泛,將記憶體分為一塊較大的Eden和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。回收時,將Eden與Survivor複製到另一塊Survivor是哪個。
預設Eden與Survivor的比例是8:1 - 標記整理演算法(Mark-Compact) 適用於老年代,將所有存活的物件都向一端移動,然後直接清理掉端邊界以外的記憶體
3 垃圾回收的其他概念
- Stop The World:從GC Roots進行可達性分析是,為了保持一致性,停頓所有的Java執行執行緒。就像時間凍結
- 準確式GC:虛擬機器可以知道記憶體中某個位置的資料具體是什麼型別
- OopMaps:用來記錄物件引用,HotSpot使用,類載入過程中,把物件內的偏移量上是什麼資料計算出來。
- 安全點:SafePoint 既程式執行時並非在所有地方都能停頓下來,只有安全點才能停頓。程式長時間執行的特徵,例如:方法呼叫、迴圈跳轉、異常跳轉等
- 搶先式中斷和主動式中斷:搶先式首先把所有的執行緒全部中斷,如果發現有執行緒不在安全點上,則回覆執行緒;主動式中斷:通過設定標誌,執行緒執行時輪詢標誌,發現標誌則自己中斷。
- 安全區域(Safe Region):如果程式不執行的時候,就沒法中斷,所以需要安全區域,一段程式碼片段中,應用關係不發生變化,則為安全區域
4 垃圾回收器
- Serial:新生代,採用複製演算法,老年代採用標記整理演算法,單執行緒,需要Stop The Worls,Client模式下的預設新生代收集器
- ParNew:Serial的多執行緒版本,新生代採用複製演算法,老年代採用標記整理演算法。Server模式的首選新生代收集器,因為目前只有它與Serial能與CMS收集器配合工作,在多CPU>2的情況下,有更好的效能
- Parallel(並行) Scavenge:新生代收集器,複製演算法,關注吞吐量,吞吐量=執行使用者程式碼的時間/(執行使用者程式碼的時間+垃圾收集時間),適合在後臺運算而不需要太多互動的任務。可以設定吞吐量大小eg:GCTimeRatio,也成為吞吐量優先收集器。可以自動控制新生代的大小、Eden與Suvivor的比例、晉升老年代的年齡,自適應調節策略是Paralle Scavenge與Parnew的最大區別
- Serial Old:serial老年代版本,client模式下使用,可以為Paralle Scavenge收集器搭配使用,或者作為CMS的後備
- Parallel Old:Parallel Scavenge的老年代版本,標記整理演算法,注重吞吐量與CPU資源敏感,可以用優先使用Parallel Scavengen+Parallel Old
- CMS(Concurrent併發 Mark Sweep):一種獲取最短回收停頓時間為目標的收集器。目前大量使用在網際網路站或者B/S系統的服務端上,尤其重視服務的響應速度。基於標記-清除演算法
-
4個步驟
1.初始標記 需要Stop the World標記一下GCRoots能夠直接關聯到的物件,速度很快
2.併發標記 進行GCRoots Tracing的過程,耗時較長,併發
3.重新標記 需要Stop the World為了修正併發標記期間因為使用者程式繼續運作
而導致標記產生變動的那一部分物件的標記記錄,比初始標記階段階段稍長,比並發標記時間短得多
4.併發清除:耗時較長,併發
5.併發重置 :這個階段,重置CMS收集器的資料結構,等待下一次垃圾回收。
CMS的優點:併發收集、低停頓
對CPU資源非常敏感,因為併發標記與併發清理的過程會佔用CPU,
預設啟動的回收執行緒數是(CPU數量+3)/4,當CPU 小於4時,佔用了不少於%25的CPU資源。
CPU越多,佔用降低,因此提出了ICMS(Incremental Concurrent Mark Sweep)增量式併發收集器
CMS無法處理浮動垃圾(Floating Garbage)因此可能出現Concurrent Mode Failure,
導致另一次Full GC的出現。
老年代使用達到一定標準,就會啟用CMS,JDK1.5預設%68,1.6預設%92,
如果執行期間預留的記憶體無法滿足程式需要,就會出現Concurrent Mode Failure,臨時啟用Serial OLD
由於使用標記-清除演算法,產生了大量空間碎片,
如果無法找到足夠大的連續空間來分配當前物件,不得不出發一下Full GC。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
G1 收集器 Garbage First。一款新的面向服務端的收集器
並行與併發:充分利用多CPU來縮短Stop The World的時間 分代收集:不需要其他收集器,可以獨立管理GC堆 空間整合:整體上是標記-整理演算法,區域性上是複製演算法 可預測的停頓:建立可預測的停頓時間模型 通過將堆空間劃分成多個相等的獨立區域,新生代與老年代不再是物理隔離的,他們都是一部分Region的集合。 有計劃的避免Full GC,G1跟蹤各個Region裡面的垃圾的價值大小 (回收所獲得的的空間大小與回收所需時間的比值), 在後臺維護一個優先列表。每次都根據允許的收集時間,優先回收價值最大的Region。 1 初始標記 標記GCRoots 能夠直接關聯到的物件,並且修改TAMS 2 併發標記 從GC roots進行可達性分析 3 最終標記 修正標記期間因為使用者程式繼續運作而導致的標記變化 4 篩選回收 制定回收計劃,進行回收,與CMS不同的是,篩選回收過程在最終標記後直接進行,需要Stop The world 由於只回收一部分Region,時間是使用者可以控制的,而且停頓使用者執行緒將大幅度提高收集效率。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
5新生代與老年代的劃分
- 物件有限分配在Eden,Eden沒空間則進行一次Minor GC(新生代GC)
- 長期存活的物件,進入老年代,預設為15次,初始為0,每經過一次Minor GC+1,預設15晉升老年代,也可以調整閥值
- 大於閥值 PretenureSizeTreshold的直接進入老年代,避免Eden與兩個Survivor產生大量的記憶體複製。
動態物件年齡判定:如果在Survivor中相同連年大小的總和大於Survivor的一般,年齡大於或者等於該年齡的物件直接進入老年代
空間分配擔當:如果老年代最大可用的連續空間大於新生代所有的物件的總空間,Minor Gc則可以確保是安全的的,可以設定是否允許擔保失敗,如果允許,則嘗試進行MinorGC,否則進行FullGC。如果MinorGC存活物件過多,出現了HandlePromotionFailure,則在失敗後發起FullGC。
一般允許擔保失敗,避免FullGC過於頻繁。
6 FullGC 、Minor Gc 、Major GC
Full==MajorGC
Minor GC:新生代垃圾回收,非常頻繁,一般速度比較快
Major Gc:老年代垃圾回收,經常會伴隨一次MinorGC,一般比MinorGC慢10倍以上
7哪些物件可作為GC Roots物件?
虛擬機器棧中應用的物件
方法區裡面的靜態物件
方法區常量池的物件
本地方法棧JNI應用的物件