author:tuiye@126.com
以MMgc為例
一
垃圾收集
垃圾收集(Garbage Collection,GC)是一種自動打掃和清除記憶體垃圾的技術,它可以有效防範動態記憶體分配中可能發生的兩個危險:因記憶體垃圾過多而引發的記憶體耗盡,以及不恰當的記憶體釋放所造成的記憶體非法引用。電腦語言中,很多利用了這一技術來自動管理與之相關聯的記憶體的清除,如Java,Perl,Python,Ruby,JavaScript等。但各自的機制不盡相同,例如Java是比較複雜的自適應GC技術,囊括Mark-Sweep,增量演算法(Incremental Algorithm)等;Perl為引用計數(Count Reference);Python採用分代機制(Generation Algorithm);Ruby是標記清除(Mark-Sweep);JavaScript的不同引擎採用的迥異,Spider monkey是標記清除(Mark-Sweep),而Tamarin是又在此之上增加了增量演算法。 以上基本囊括了比較流行的GC演算法,除此之外還有複製(Copying)演算法與標記整理(Mark-Compact)演算法等。這些演算法各自有自身的優勢,有的實現簡單,有的回收及時(也可說記憶體峰值可以保持在較低水準),還有些可以用於即時系統(即每次收集不會佔用很大CPU時間,造成停頓感),因此對於不同需求有應採用不同的方式。譬如一個需要進行即時垃圾收集的運行環境採用增量收集是一個比較好的選擇。
二
增量演算法理論與三元色機制 增量收集演算法的基礎仍是傳統的標記清除和複製演算法。增量收集演算法通過對進程間衝突的妥善處理,允許垃圾收集進程以分階段的方式完成標記、清理或複製工作。增量演算法的具體機制可以用不同,但其思想都是把堆棧分為多個域,每次僅從一個域收集垃圾,從而造成較小的應用程式中斷,其中比較著名的是火車(Train)機制與三色(三元色,Tri-Color)標記機制。以下介紹一下三元色機制的概念。 在垃圾收集中,所有的對象可能出於其下的三種顏色中的一種:黑色,灰色與白色。各自代表: 黑色(black):表示此節點已被訪問到,且是live的(其子節點也被訪問到),不會被回收(reclaimed); 灰色(gray):表示此節點已在處理列表中,但其子節點尚未被檢查; 白色(white):表示此節點沒有訪問過,在GC完成後被視為垃圾對象; 在標記之前先將堆中所有的配置單位置成白色,然後按深度優先演算法遍曆每一個單元。當垃圾收集器遍曆一個分支的時候,如果一個配置單位及與之相關聯的單元都被遍曆到,則將其標記成黑色。如果一個單元被遍曆到,但是與之相關聯的單元尚未被遍曆,則將該單元標記成灰色。這時,垃圾收集器將繼續遍曆與該灰色單元相關聯的單元,直到這些相關聯的單元全部被遍曆到,才能將這個灰色單元標記成黑色。最後當所有被遍曆到的單元都被標記成黑色的時候, 將堆中被標記成白色的配置單位回收。 收集器處理過程中,去檢測節點是否是能到達的(reachable),此活動中依靠找到從灰色節點到白色節點的邊緣與把白色節點染色成灰色。因此每步跟蹤包含選擇一個灰色節點並且把其白色子節點標記成灰色。[1] 灰色節點只有可能串連到另外的灰色的節點或黑色的節點,那麼把它標記為黑色;[2] 當沒有灰色的節點剩下的時候,所有可到達的部分都已找到,餘下的白色的節點都被回收。 注意,黑色節點不可能有白色的子節點!也就是說黑色節點不能指向白的節點,這一點叫做不變數(invariant)。 為了保護與防止此種情況的發生,引入了讀屏障(Read Barrier)與寫屏障(Write Barrier)。讀屏障:當mutator儲存一個從黑色轉到白色的節點時引用,把其父或子節點置成灰色;(Detects an attempt to read a white object and immediately colors it gray)x.f = y; -> black2gray(x).f = y;寫屏障:當mutator請求一個白色節點時,把它置成灰色;(Traps attempts to write a pointer into an object)x.f = y; -> x.f = white2gray(y);
三
一個實現
MMgc http://wiki.mozilla.org/Tamarin::MMgc 在以上網址中,對Tamarin中實現的MMgc做了一個比較全面的闡述。當然在MMgc中不僅僅用了增量技術,但這裡我們著重對增量技術做說明。 [1] 所有在GC中的根(s)(roots)被壓入隊列(queue),此時所有根(s)為gray,而除此之外的都為white; [2] 在隊列(queue)處理過程中,所有live objects有2種可能變化,從gray到black,從white到gray; [3] 當一個指向white對象的指標寫入一個black對象的時候,此時不得不中斷其寫入行為,把white放入隊列(queue),(註:這就是寫屏障);當然此時還有另一種辦法,就是把black對象放入隊列,此種方式好處是當很多white對象寫入同一個black對象是,我們只需要壓入一次black對象,這樣特別是當black對象是一個很大的數組的時候,對效率提高是比較有用的。另一方面,如果black對象的數組很大,而寫入此對象的新的white對象很少,那麼mark一個很大的black對象也是很低效的事件; 所以引入一個比較流行的解決方案,叫做卡片標記(card marking),不過MMgc未作實現(MMgc作的是把black對象移到gray,即壓入queue),其理論如下:(略,MMgc未作實現) 增量收集的時間片 當前MMgc中,決定何時收集(collect)行為的是基於多少記憶體已被分配出來了,如果現在分配出來的記憶體佔heap記憶體的一定比例以上的時候,MMgc會做收集(collection)。相似地,標記(mark)也可以基於以上的方式,當ISD(incremental start divisor)為4時候,那麼只有heap的記憶體餘下1/4的時候,就開始標記;當ISD為1的時候,意味著標記是經常要做的。 決定時間片的因素有2個:[1] the rate at which we can trace memory[2] the rate at which the mutator is requesting more memory
四
參考文獻[1] GARBAGE.COLLECTION.Section6.pdf[2] Wirth.ppt[3] Incremental Tracing Collectors.pdf[4] thesis-newgc.pdf[5] garbagecollection.pdf[6] orp.pdf[7] Scheduling.Garbage.Collection.in.Embedded.System.pdf[8] hirzel-dissertation.pdf[9] color.pdf[10] ASM.ppt[11] 垃圾收集趣史[12] 記憶體回收行程基礎與效能提示(card marking)[13 ] Uniprocessor Garbage Collection Technique.ppt (tri-color)[14] Incremental Mature Garbage Collection Using the Train Algorithm.htm (card marking)