為什麼CMS兩次標記時要 stop the world(阿里面試)
1、CMS及其執行過程?
CMS,全稱Concurrent Mark and Sweep,用於對年老代進行回收,目標是儘量減少應用的暫停時間,減少full gc發生的機率,利用和應用程式執行緒併發的垃圾回收執行緒來標記清除年老代。CMS並非沒有暫停,而是用兩次短暫停來替代序列標記整理演算法的長暫停。
內外的設定正常收集週期是這樣的:
1)CMS-initial-mark 初始標記 2)CMS-concurrent-mark 併發標記的 3)CMS-concurrent-preclean 執行預清理 注: 相當於兩次 concurrent-mark. 因為上一次c mark,太長.會有很多 changed object 出現.先幹掉這波.到最好的 stop the world 的 remark 階段,changed object 會少很多. 4)CMS-concurrent-abortable-preclean
執行可中止預清理 5)CMS-remark 重新標記 6)CMS-concurrent-sweep 併發清除 7)CMS-concurrent-reset 併發重設狀態等待下次CMS的觸發其中,CMS-initial-mark和CMS-remark會stop-the-world。
2、為什麼 CMS兩次標記時要 stop the world?
我們知道垃圾回收首先是要經過標記的。物件被標記後就會根據不同的區域採用不同的收集方法。看上去很完美的一件事情,其實並不然。 大家有沒有想過一件事情,當虛擬機器完成兩次標記後,便確認了可以回收的物件。但是,垃圾回收並不會阻塞我們程式的執行緒,他是與當前程式併發執行的。所以問題就出在這裡,當GC執行緒標記好了一個物件的時候,此時我們程式的執行緒又將該物件重新加入了“關係網”中,當執行二次標記的時候,該物件也沒有重寫finalize()方法,因此回收的時候就會回收這個不該回收的物件。 虛擬機器的解決方法就是在一些特定指令位置設定一些“安全點”,當程式執行到這些“安全點”的時候就會暫停所有當前執行的執行緒(Stop The World 所以叫STW),暫停後再找到“GC Roots”進行關係的組建,進而執行標記和清除。 這些特定的指令位置主要在:
- 1、迴圈的末尾
- 2、方法臨返回前 / 呼叫方法的call指令後
- 3、可能拋異常的位置