lua中的循环引用辨析

对于任何垃圾收集机制(gc),不可避免的一个问题是循环引用,即:

a引用b,b引用c,c引用a

因为自动收集机制大部分是通过引用计数来完成的,简单的引用机制在上述情况下会歇菜,因为a,b,c都被引用了所以简单的引用机制是不会将他们回收的。

那么lua的gc能不能处理循环引用呢?我们来做一个测试:

--启动gc回收并打印回收结果函数
function memColl()
	print("now collect")
	collectgarbage("collect")
	local c1 = collectgarbage("count")
	print("after collect , mem used is %d", c1)
end

--开始分配前
collectgarbage("collect")
local c1 = collectgarbage("count")
print("before new, mem used is %d", c1)

--开始分配
local t = nil
for i = 1, 1000000, 1 do
	--t通过t.v与t.v.tRef构成循环引用
	t = {}
	t.v = {}
	t.v.tRef = t
end

local c2 = collectgarbage("count")
print("after new, mem used is %d", c2)

--多次回收
memColl()
memColl()
memColl()
memColl()
启动运行查看结果:

lua中的循环引用辨析_第1张图片

可以看到,内存是被回收了的,也就是说lua的gc是能处理循环引用的。


弱引用和循环引用不是一回事,lua中的弱引用有如下好处(摘录自他人的博客):

lua里面也有弱引用,虽然lua的垃圾收集器可以保证没有循环引用的问题,但是lua引用在内存泄漏方面还是有重要意义,在工作实践中,lua的弱引用table(weak table)常被用来检测内存泄漏问题,因为是弱引用并不阻止GC,把要监测的对象放入weak table中,过一段时间,该对象本该要释放,但是在weak table中仍然能检索到此对象,表示此对象泄漏了。演示代码如下:
MemLeakChecker = {}
setmetatable(MemLeakChecker, {__mode="v"})
local Obj = {["Name"] = "Obj1"}
MemLeakChecker["obj1"] = Obj

function DestroyObj()
     Obj = nil
end

DestroyObj()

assert(not MemLeakChecker["obj1"])

 代码其实没有更好的演示出内存泄漏检测的功能,看起来Obj在这里很难泄漏,但是在真正的工作代码中,lua工程常常有成千上万行代码,不同模块有意或无意的引用了一些全局变量,使得GC无法释放,运行久了后,内存消耗巨大,这时使用weak table实时检测跟踪内存泄漏就相当有意义了。 


你可能感兴趣的:(lua那些事)