Lua GC

一、GC的原理及其算法設計

不同的語言,對GC算法的設計不同,常見的GC算法是引用計數和Mark-Sweep算法, c#采用的是Mark-sweep && compact算法, Lua采用的是Mark-sweep算法,分開說一下:

引用計數算法:在一個對象被引用的情況下,將其引用計數加1,反之則減1,如果計數值為0,則在GC的時候回收,這個算法有個問題就是循環引用。

Mark-sweep算法:每次GC的時候,對所有對象進行一次掃描,如果該對象不存在引用,則被回收,反之則保存。

在Lua5.0及其更早的版本中,Lua的GC是一次性不可被打斷的過程,使用的Mark算法是雙色標記算法(Two color mark),這樣系統中對象的非黑即白,要么被引用,要么不被引用,這會帶來一個問題:在GC的過程中如果新加入對象,這時候新加入的對象無論怎么設置都會帶來問題,如果設置為白色,則如果處于回收階段,則該對象會在沒有遍歷其關聯對象的情況下被回收;如果標記為黑色,那么沒有被掃描就被標記為不可回收,是不正確的。

為了降低一次性回收帶來的性能問題以及雙色算法的問題,在Lua5.1后,Lua都采用分布回收以及三色增量標記清除算法(Tri-color incremental mark and sweep)


每個新創建的對象顏色設置為白色

//初始化階段

遍歷root節點中引用的對象,從白色置為灰色,并且放入到灰色節點列表中

//標記階段

while(灰色鏈表中還有未掃描的元素):

從中取出一個對象,將其置為黑色

遍歷這個對象關聯的其他所有對象:

if 為白色

標記為灰色,加入到灰色鏈表中(insert to the head)

//回收階段

遍歷所有對象:

if 為白色,

沒有被引用的對象,執行回收

else

重新塞入到對象鏈表中,等待下一輪GC

二、GC的數據結構

分析Lua中對于需要GC的類型數據

define iscollectable(o) (ttype(o) >= LUA_TSTRING)

都會有一個基本的定義CommonHeader,其定義為:


image.png

next: GCObject鏈表指針,該指針用來將所有的GC對象都鏈接在一個表中;

tt: 數據類型:nil, boolean, number, string...

marked: 標記字段,byte表示的字段顏色定義為


image.png

這兒特定解釋一下為什么會有兩種白色,前面提到,5.1后的Lua采用的是三色標記算法,其實質是四色標記算法,分為0型白色和1型白色,在GC回收的時候,會設置當前的白色為其中一種,詳見globalstate中的currentwhite,這樣在代碼回收的時候,如果當前對象的白色不為currentwhite,則認為其不可回收,這樣的對象需要等到下一次的GC才能決定是否回收,具體參看后面的,會有對應的應用。對于global_state的設計為:


image.png

參考《Lua設計與實現》
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。