GC(垃圾回收)必須Stop-the-world?
阿新 • • 發佈:2019-12-31
GC(垃圾回收)必須Stop-the-world?
併發程式設計的許多困難都源於物件生存期問題,當物件線上程之間傳遞時,要確保它們安全地釋放就變得很麻煩。因此GC可以使得併發程式設計變得容易。但是實GC也是一個挑戰,但是一次實現,就可以解決人們手動管理記憶體的麻煩(C語言),大大提高的開發效率和避免了許多Bug。
但是GC也是有成本的,他會影響程式的效率,GC是一個非常挑戰的工作,很多電腦科學家在上面耗費了數十年不斷的提升效率。
GC演演算法設計時,會考慮幾個重要指標:
- 程式吞吐量:GC對程式效率的影響,也就花費在GC的時間和程式處理正常業務的時間比;
- GC吞吐量:單位時間內垃圾回收的數量;
- 暫停時間:Stop-the-world 的時間;
- 併發:垃圾回收機制如何使用多核;
- 等等還有很多
很多人問為什麼GC的時候要暫停(Stop-the-world)整個程式,為什麼不能併發的執行GC呢?GC本質上是一種權衡,Stop-the-world 是為了GC吞吐量(在給定CPU時間內多少垃圾可以被收集器清除?),便不是說GC必須STW,你也可以選擇降低執行速度但是可以併發執行的收集演演算法,這取決於你的業務。
J9VM中標記階段有描述,標記分為:
- 並行標記
並行標記的目的是在不降低單處理器系統上標記效能的情況下,提高多處理器系統上典型標記的效能。 通過增加共享使用工作包池的助手執行緒,可以提高物件標記的效能。例如,可選取由一個執行緒返回給池的完整輸出包作為另一個執行緒的新輸入包。 並行標記仍需要一個用作主協調代理程式的應用程式執行緒的參與。助手執行緒幫助標識回收的根指標並跟蹤這些根。標記位是使用不需要附加鎖的主機原子原語來更新的 複製程式碼
- 併發標記
在堆大小增加時,併發標記能夠提供縮短且一致的垃圾回收暫停時間。 在堆滿之前,GC 將啟動併發標記階段。在併發階段,GC 掃描堆,檢查根物件,比如堆疊、JNI 引用和類靜態欄位。通過要求每個執行緒掃描自己的堆疊來掃描堆疊。隨後,這些根將用於併發跟蹤活動物件。線上程執行堆鎖分配時,跟蹤由低優先順序的後臺執行緒和每個應用程式執行緒執行。 當 GC 利用正在執行的應用程式執行緒併發標記活動物件時,必須記錄對已跟蹤物件的任何更改。它使用在每次更新物件中的引用時執行的寫屏障。在發生物件引用更新時,寫屏障將使用標誌。使用該標誌迫使對部分堆重新掃描。 複製程式碼
比如:你做金融交易類的專案,分秒必爭,那可以選擇並行的方式。如果你是一種後臺任務,比如資料處理,那你可以選擇STW型別演演算法,使 GC 的吞吐量得到最高。
兩類演演算法最終的權衡指標就GC效率:程式工作時間與執行收集時間的比率。
沒有單一的演演算法在所有方面都完美,語言也不可能知道程式的業務型別,這也就是“GC調優”存在的原因。這也是科學的基礎規律。