【理解HotSpot虛擬機器】序列垃圾收集器Serial和Serial Old原理
上一篇GC垃圾收集器的對比分析分析和對比了JVM中常見的垃圾收集器,本篇先來探究序列垃圾收集器的原理。
1 Serial 收集器
Serial 收集器是在 DefNewGeneration 新生代上實現收集的,DefNewGeneration上分為3個區:eden 區、 from區和 to 區。Serial 收集器使用複製演算法進行回收複製演算法的思想是將eden和from區活躍的物件複製到to區,並清空eden區和from區,如果to區滿了,那麼部分物件將會被晉升移動到老年代,隨後交換from和to區。
假設我們有如下狀態的 DefNewGeneration 需要收集:
Step 1
遍歷當前記憶體代中所有根物件,eden和from區的根物件將被複制到to區,形成T0物件集
複製eden的根物件
Step 2
遍歷更低記憶體代(DefNewGeneration無更低記憶體代)和更高記憶體代物件(TenuredGeneration)所有物件(實際中無需遍歷所有,而是通過Card Table解決),如果這些物件有引用當前記憶體代的物件,則把物件複製到to區,形成T0物件集
遍歷其他記憶體代的物件
Step 3
通過廣度優先搜尋演算法遍歷掃描活躍物件,即T0物件集
從T0集合開始廣度優先演算法
Step 4
如果Eden區中的物件的age達到_tenuring_threshold,則不是將物件複製到to區,而是提升到高一代(TenuredGeneration)
6號物件的age超過_tenuring_threshold
Step 5
如果to區滿了,eden區中的存活物件也將被提升到高一代(TenuredGeneration)
7號物件因to區滿了也提升到Old區
Step 6
- 清除eden區和from區
- 交換from區和to區地址
小結
- 進行GC前需要確定(1)to區為空;(2)下一個記憶體代有足夠的記憶體容納新生代的所有物件
- Step 1 - Step 3被稱為可達性分析
2 Serial Old 收集器
Serial Old 收集器是在 TenuredGeneration 老年代上實現收集的,Serial Old 收集器 所使用的垃圾回收演算法是標記-壓縮-清理演算法。在回收階段,將標記物件越過堆的空閒區移動到堆的另一端,所有被移動的物件的引用也會被更新指向新的位置。
假設我們有如下狀態的 TenuredGeneration 需要收集:
Step 1 遞迴標記所有活躍物件
與DefNewGeneration類似,以
- 當前記憶體代中所有根物件
- 在當前代中,被更低記憶體代(DefNewGeneration)和更高記憶體代物件(TenuredGeneration無更高代)任意物件引用的當前記憶體代的物件
為初始集合,採用廣度優先演算法查詢當前代中的存活物件
Step 2 計算所有活躍物件在壓縮後的偏移地址
遍歷所有的物件,為存活物件重新計算新物件的地址,並將新地址設定為存活物件的轉發指標
Step 3 更新物件的引用地址
遍歷各記憶體代物件/引用,若物件所引用的物件已經被標記,則更新其引用地址為轉發指標所轉向的新地址。
Step 4 移動所有活躍/存活物件到新的位置
遍歷TenuredGeneration物件,對於存活物件,複製原物件的資料內容到壓縮後的地址(即轉發指標的地址),並初始化新的位置的物件的MarkWord
小結
- 用廣度優先方法作可達性時,DefNewGeneration 是用to區來儲存結果,而 TenuredGeneration 是用一個臨時stack來儲存結果
- 標記物件:設定物件的物件頭為被標記狀態,有些物件的物件頭可能包含一些資訊,需要在GC結束之後進行恢復,所以標記前需儲存物件和對應的物件頭