三色標記演算法原理詳述及CMS和G1如何解決其併發標記問題
三色標記演算法是CMS和G1在併發標記階段都普遍採用的一種trace演算法
首先,為什麼要對物件進行標記?
因為tracing的過程中你必須對已經遍歷過、正在遍歷、還沒有遍歷到的物件進行區分,如果不進行區分的話,那你tracing有什麼意義呢?每次某個垃圾回收執行緒重新獲得了cpu的時間分片,回來之後發現自己根本啥都不記得了,遍歷過哪些物件(是否是垃圾)已經全忘了,只能從頭重新tracing... 這是一個非常嚴重的問題!!!
因此為了有效的對是否遍歷過的物件的狀態進行區分,便有了這個三色標記的演算法,其思想很簡單,那就是將我剛剛提到的物件的三種狀態用不同的顏色進行標記,如果這個物件及物件的引用物件全部都tracing完了,那麼這時候我就可以將物件標記為黑色,而如果物件本身已經遍歷過了,但是物件所引用的那些孩子物件還沒有遍歷過,這時候我可以將物件標記為灰色,如果物件完全沒有遍歷過(物件本身 + 物件的引用孩子),那麼此時我就可以將物件標記為白色,這樣一來,即使發生了執行緒切換,因為在物件頭(hotspot)裡面存在著物件的顏色標記,仍然看可以從上次遍歷過的地方繼續遍歷,tracing就可以了
這個過程感覺有點類似於層序遍歷演算法BFS,每次我tracing一層,然後如果孩子不為空的話,將孩子都入佇列,然後將本身標記為灰色,之後就不斷的從佇列中取孩子,如果孩子全部都遍歷完了,那麼這時候就可以將原來的父節點,置為黑色,以後便可以不再找這個黑色父節點的麻煩了!
剛剛我解釋的過程如果用一張圖來表示的話,大概就是這樣,三種顏色代表著tracing的三種 不同的狀態!
但是我們知道,不論是CMS還是G1的垃圾回收的過程中,併發標記都是和使用者執行緒一起進行的,這會帶來什麼問題呢?
你一邊遍歷tracing,但是發現物件間的引用關係還在不斷的發生變化,這個過程是不是有點太扯了,讓垃圾收集器很難做啊!(真的太難了T T)
具體說的話會帶來哪些問題呢? 一共分為兩種case:
1.部分物件會存在遍歷不到的問題