基本算法
- 標記-清除算法由 標記階段 和 清除階段 構成。
- 標記即將所有活動的對象打上標記。
- 清除即將那些沒有標記的對象進行回收。
標記與清除
- 遍歷GC root引用,遞歸標記(設置對象頭中的標志位)對象。
- 標記時如果標志位表示已經標記過則可以跳過。
- 遍歷對象有深度優先與廣度優先兩種算法,其搜索的步驟數一致,而深度優先的內存使用量更小,因此一般使用深度優先。
- 清除階段將再次遍歷堆,未標記的對象加入到空閑鏈表中,標記的對象則去除標記。
分配與合並
- 分配指mutator(Application)申請分塊時獲取內存塊的過程。
- 分配即通過搜索空閑鏈表,找到一個大小合適的塊。分配測量有如下:
- First-fit,找到第一個大於要求大小的塊即返回。
- Best-fit,找到比要求大小大的最小塊。
- Worst-fit,找出最大的塊將其分割成要求大小塊和剩余的,一般不使用(容易產生碎片)
- 對於內存中連續的垃圾可以對其進行合並,減少碎片。
優缺點
優點
- 算法實現簡單。
- 與保守式GC算法兼容(對象不能被移動)。
缺點
- 碎片化。
- 分配速度慢,每次分配需要遍歷空閑鏈表。
- 與寫時復制(copy-on-write)沖突,因為做GC時需要將對象頭進行標記,這將導致大量的數據發生復制。
- STW(Stop-The-World)長,兩個階段均要遍歷整個堆。
改進
多個空閑鏈表
針對分配速度慢
- 根據塊的大小建立不同的空閑鏈表,相同大小的塊鏈接到相同鏈表中。
- 由於對於大塊的申請比較少,因此主要針對小塊建立鏈表,對於大塊的可以都在同一個鏈表中,如大於2-100的分別建立各自大小的鏈表而大於100的都寫入一個大塊鏈表。
BiBOP
針對碎片化
- 原理:將大小相近的對象整理成固定大小的塊進行管理。
- 把堆分割成固定大小的塊,讓每個塊只能配置同樣大小的對象。
- 但是並不能很好的消除碎片化,如果對堆的分隔沒控制好反而可能導致堆的利用率。
位圖標記
針對寫時復制
- 由於GC過程需要修改對象中屬性導致寫時復制不兼容,因此指收集各個對象的標志位並表格化。
- 將堆中的對象與位圖對應上,而后通過位圖的標志代表堆中對象的標志。
- 優點:
- 兼容寫時復制
- 清除階段可以快速的去除標記。
延遲清除法
針對STW過長
- 延遲清除法(Lazy-Sweep)是縮減清除操作而導致的mutator STW的方法。
- 標記結束后不做清除操作而是在分配操作中進行。
- 在分配時,從上次遍歷結束的地方開始使用First-fit查找塊,如果找不到返回NULL,此時進行標記階段而后再次進行First-fit查找。還找不到則分配失敗。
