弱引用表
用来告知Lua语言一个引用不应阻止对一个对象回收的机制。
弱引用:是一种不在垃圾收集器考虑范围内的对象引用。
一个表是否为弱引用表是由其元表中的__mode
字段所决定的。
a ={}
mt = { __mode = "k"}
setmetatable(a, mt) --现在'a'的键是弱引用的了
key = {} --创建第一个键
a[key] = 1
key = {} --创建第二个键
a[key] = 2
collectgarbage() --强制进行垃圾回收
for k, v in pairs(a) do
print(v) -->2
end
调用
collectgarbage
强制垃圾收集器进行一次完整的垃圾收集。
析构器
析构器是一个与对象关联的函数,当该对象即将被回收时该函数会被调用。
使用元方法__gc
来实现析构器
o = {x = "hi"}
setmetatable(o, {__gc = function(o) print(o.x) end})
collectgarbage() --> hi
o = {x = "hi"}
mt = {}
setmetatable(o, mt)
mt.__gc = function(o)
print(o.x)
end
o = nil
collectgarbage() -->(prints nothing)
这里,我们确实给对象o设置了元表,但是这个元表没有
__gc
元方法,因此对象没有被标记为需要进行析构处理。即使我们后续给元表增加了元方法__gc
,Lua语言也发现不了这种赋值的特殊之处,因此不会把对象标记为需要进行析构处理。
o = {x = "hi"}
mt = {__gc = true}
setmetatable(o, mt)
mt.__gc = function(o)
print(o.x)
end
o = nil
collectgarbage() -->(prints nothing)
现在,由于元表有了__gc字段,因此对象会被正确地标记为需要析构处理。
当垃圾收集器在同一个周期中析构多个对象时,它会按照对象被标记为需要析构处理的顺序逆序调用这些对象的析构器。
例:创建了一个由带有析构器的对象所组成的链表:
mt = {__gc = function (o) print(o[1])end}
list = nil
for i = 1, 3 do
list = setmetatable({i,link = list}, mt)
end
list = nil
collectgarbage()
--> 3
--> 2
--> 1
控制垃圾收集的步长
通过函数collectgarbage可以对垃圾收集器进行一些额外的控制
collectgarbage("stop")
:停止垃圾收集器,直到使用选项"restart"
再次调用collectgarbage
collectgarbage("restart")
:重启垃圾收集器。collectgarbage("collect")
:执行一次完整的垃圾收集,回收和析构所有不可达的对象。这是默认的选项collectgarbage("step")
:执行某些垃圾收集工作,第二个参数data指明工作量,即在分配了data个字节后垃圾收集器应该做什么。collectgarbage("count")
:以KB为单位返回当前已用内存数,该结果是一个浮点数,乘以1024得到的就是精确的字节数。该值包括了尚未被回收的死对象。collectgarbage("setpause")
:设置收集器的pause参数(间歇率)。参数data以百分比为单位给出要设定的新值:当data为 100时,参数被设为1(100%)。collectgarbage("setstepmul")
:设置收集器的stepmul参数(步进倍率, step multiplier)。参数data给出新值,也是以百分比为单位。
参数pause
用于控制垃圾收集器在一次收集完成后等待多久再开始新的一次收集
参数stepmul
控制对于每分配1KB内存,垃圾收集器应该进行多少工作。
例如,如果我们不想让垃圾收集在某些阶段运行,那么可以通过调用函数
collectgarbage("stop")
停止垃圾收集器,然后再调用collectgarbage("restart")
重新启动垃圾收集器。在一些具有周期性休眠阶段的程序中,可以让垃圾收集器停止,然后在程序休眠期间调用collectgarbage("step", n)
。要设置在每一个休眠期间进行多少工作,要么为n实验性地选择一个恰当的值,要么把n设成零(意为最小的步长),然后在一个循环中调用函数collectgarbage
直到休眠结束。