垃圾回收教學

lua-users home
wiki

不可到達的區域

在 C 和 C++ 等語言中,我們在執行階段建立的物件(例如使用 malloc()new),必須特別刪除。記憶體外洩是指物件已配置,但遺失且從未釋放的結果。我們可以撰寫記憶體追蹤系統,為我們配置記憶體,並在不再需要時通知我們。有些語言有內建這個功能,例如 Lua。

追蹤哪些記憶體物件不再需要的方式有很多。只要沒有任何應用程式變數參照某個物件,就表示該物件為不可到達。不再可被到達的物件會變成可刪除物件,為自動清除或垃圾回收的候選者。

以下範例中,我們建立了一些 Lua 物件,並將它們指定給變數。如果我們為變數指定其他值,而且沒有其他變數參照先前的物件,則這些物件會變成不可到達。若沒有垃圾回收,就會造成記憶體外洩。例如:

> t = { this="table"; 1,2,3 }  -- construct a table and assign it to "t"
> t = nil                      -- set "t" to nil and the table becomes unreachable
>
> s = "a string"               -- create string variable
> s = "another string"         -- when set to another value the old value becomes unreachable

簡單的回收演算法

有多種不同類型的收集器,而且有許多與垃圾回收相關的術語 [1]。其中一種最簡單的回收演算法是參考計數。在此方法中,我們只在每個配置的物件中保留一個計數,計算參照(或使用)該物件的物件數量。如果參照另一個物件的物件數量降為零,該物件便會變為不可到達(且未使用),而且可以釋放。這種方法的複雜之處在於循環參照,A 物件參照 B 物件,而 B 物件參照 A 物件。只要其他物件參照 A 物件和/或 B 物件,這種情形並無不妥,但當它們不再參照時,A 物件和 B 物件將形成一個孤立區域。現在,它們是一組不可到達的物件,而且因為循環參照而彼此永久存在。除非擴充參考計數收集演算法,否則這個孤立區域永遠無法釋放。例如:

> a = {}
> b = {}
> a['other'] = b
> b['other'] = a   -- now we have a cyclic reference
> a,b = nil,nil    -- oh dear, we don't have a reference to the 2 tables now
>                  -- there are two tables which are unreachable

標記與清除

若要從上述演算法中清除孤立區域,我們可以遍歷系統中的所有變數,並查看它們參照哪些物件。如果變數發現某些物件不可到達,則我們可以對其執行垃圾回收。這種演算法稱為標記與清除,亦即我們標記所有可到達的物件,並清除剩下的物件。Lua 專門使用標記與清除垃圾回收演算法。這種方法的優點是不必計算物件的參照數目,也就不會有循環參照的問題。缺點是,處理此演算法需要時間,而且在即時應用程式中可能會產生問題。

注意:如果我們將標記與清除回收演算法的處理分布開來,使其不再一次執行完畢,對於主機系統而言,這個處理程序便會更透明。這稱為增量垃圾回收。Lua 版本 5.1 已針對這個變更進行修改。

控制和狀態

Lua 提供一些函式用於控制及查詢垃圾回收的狀態。在 CoreFunctionsTutorial 中有更詳細的資訊。

延伸讀物

參閱參考手冊 [3] 的第 2.10 章節。

Wiki 中的其他頁面更詳細地介紹了 Lua 中的垃圾回收機制。建議閱讀以下文章


RecentChanges · preferences
edit · history
上次編輯 2010 年 7 月 8 日 下午 1:14 GMT (diff)