1. 程式人生 > 其它 >Lua五:"collectgarbage"、 弱引用table、析構器

Lua五:"collectgarbage"、 弱引用table、析構器

Lua具有自動記憶體回收機制,但是垃圾收集器只能回收那些它認為是垃圾的東西,不會回收那些使用者認為是垃圾的東西。比如將一個物件放在一個數組中但沒有用時,它就無法被回收,這是因為即使當前沒有其他地方在使用它,但陣列仍引用著它,除非使用者告訴Lua這項引用不應該阻礙此物件的回收,否則Lua是無從得知的。

Lua垃圾回收函式collectgarbage,這個函式是垃圾回收機制的一個通用介面,其第一個引數是字串,代表操作型別,第二個引數只有某些操作有,是該操作所需要的引數。其原型:collectgarbage ([opt [, arg]])

操作型別:

  • "collect":執行一個完整的垃圾回收週期,這是一個預設的選項。
  • "stop":停止垃圾收集器(如果它在執行),直到再次使用操作為"restart"的圾回收函式collectgarbage。
  • "restart":將重新啟動垃圾收集器(如果它已經停止)。
  • "count":返回當前使用的的程式記憶體量(單位是Kbytes)。
  • "step":執行垃圾回收的步驟,這個步驟的大小由引數arg(較大的數值意味著較多的步驟)以一種不特定的方式來決定,如果你想控制步驟的大小,你必須實驗性的調整引數arg的值,如果這一步完成了一個回收週期則函式返回true。
  • "setpause":第二個引數pause 用於控制垃圾收集器在一次收集完成後等待多久再開始新的一次收集。當值為零時表示 Lua語言在上一次垃圾回收結束後立即開始一次新的收集。當值為200%時表示在重啟垃圾收集器前等待記憶體使用翻番。如果想使消耗更多的CPU時間換取更低的記憶體消耗,那麼可以把這個值設得小一點。通常,我們應該把這個值設在О到200%之間。
  • "setstepmul":引數stepmul控制對於每分配1KB記憶體,垃圾收集器應該進行多少工作。這個值越高,垃圾收集器使用的增量越小。一個像100000000%一樣巨大的值會讓收集器表現得像一個非增量的垃圾收集器。預設值是 200%。低於100%的值會讓收集器執行得很慢,以至於可能一次收集也完不成。

兩個引數pause和stepmul控制著垃圾收集器的角色。任何垃圾收集器都是使用CPU時間換記憶體空間。在極端情況下,垃圾收集器可能根本不會執行。但是,不耗費CPU時間是以巨大的記憶體消耗為代價的。在另外一種極端的情況下,收集器可能每進行一次賦值就得執行一次完整的垃圾收集。程式能夠使用盡可能少的記憶體,但是是以巨大的CPU消耗為代價的。pause 和stepmul的預設值正是試圖在這兩個極端之間找到的對大多數應用來說足夠好的平衡點。

選項setpause的使用方法:collectgarbage("setpause", 200),表示當收集器在總使用記憶體數量達到上次垃圾收集時的兩倍時再開啟新的收集週期。

選項setstepmul的使用方法:collectgarbage("setstepmul", 200),表示垃圾收集器的執行速度是記憶體分配的2倍,如果此值小於100可能會導致垃圾回收不能形成完整的週期。

table中有key和value,這兩者都可以包含任意型別的物件。通常,垃圾收集器不會回收一個可訪問table中作為key或value的物件。也就是說,這些key和value都是強引用,它們會阻止對其所引用物件的回收。在一個弱引用table中,key和value是可以回收的。

弱引用table(weak table)是使用者用來告訴Lua一個引用不應該阻礙對該物件的回收。所謂弱引用,就是一種會被垃圾收集器忽視的物件引用。如果一個物件的引用都是弱引用,該物件也會被回收。

弱引用table有3種類型:1、具有弱引用key的table;2、具有弱引用value的table;3、同時具有弱引用key和value的table;

table的弱引用型別是通過其元表中的__mode欄位來決定的。這個欄位的值應為一個字串:如果包含'k',那麼這個table的key是弱引用的;如果包含'v',那麼這個table的value是弱引用的;

弱引用table的一個例子,這裡使用了collectgarbage函式強制進行一次垃圾收集:

 1 a = {}
 2 setmetatable(a, {__mode='k'})
 3 
 4 key = {}
 5 a[key] = 'key1'
 6 
 7 key = {}
 8 a[key] = 'key2'
 9 
10 collectgarbage()

該段程式碼“collectgarbage()”執行前,表a同時存在key為{}和value為'key1'和'key2'的物件,“collectgarbage()”執行後,只存在key為{}和value為'key2'的物件。

析構器_gc簡單來說,就是當一個table的元表中存在_gc時,就會在這個lua table被gc釋放掉之前,呼叫的函式。不過,在5.2之前,_gc只能用在userdata中,而5.2及5.2之後,table也可以用__gc了。

 1 function class(name, super)
 2    ...
 3     -- 解構函式
 4     if cls.dtor then
 5         cls.dtor = function(self) end
 6     end
 7 
 8     cls.__meta = {__index = cls, __gc = function(self) self:dtor() end}
 9     cls.new = function(...)
10         local obj = setmetatable({}, cls.__meta)
11         obj:ctor(...)
12         return obj 
13     end
14     return cls
15 end