上次写了一个lua内存泄露检测的脚本,现在将它的实现原理拿出来和大家分享一下,希望能有所帮助。
lua内存泄露:
首先第一点,lua中的内存泄露和我们所说的c/c++中的内存泄露本质上是不一样的。
lua中有垃圾回收机制(GC),所以理论上是不会有内存泄露的。当它进行GC的时候,会从根部开始扫描所有的对象,如果某个地方对这个对象还有引用,就不会把这个对象内存collect,这个对象就没有被GC。
所以lua中的内存泄露是指那些:已经没有被使用了,但外部依然还有引用存在的对象。
举个例子:函数中应该被申明为local的对象忘记加local
local function test()
testTable = {} --这个testTabel会被存放在全局表_G中,GC时由于此对象还有引用存在,所以这里总是会有一个table泄露。
local mt = {} --mt加了local修饰,函数调用完后,引用也不复存在了,GC时会被回收。
setmetatable(testTable, mt)
end
检测原理:
lua中支持垃圾回收机制的对象有五种:string,table,function,full userdata,thread。而他们的引用直接或间接的保存到:lua_state对象,_G全局表,Registry注册表,global_state->mt中。
所以我们就可以在脚本层次实现内存泄露的检测模块。
lua中有一种叫weak表的东东,它的metatable中的__mode被设置为“k","v"或者”kv",表示保存在它中的键或值或键值都是一种弱引用状态。
若一个对象的所有引用都是弱引用了,那么这个对象也会被GC回收掉,所以对应的weak表中此对象的入口就没有了。
所以我们可以用另外一种实现:就是把用户自己创建的资源对象统统都丢到weak表中,运行完程序后强制GC,然后去查看weak表,若表中还保存着那个对象,就意味着这个对象还有外部引用(相对弱引用我们就叫它为强引用吧),资源没有被GC掉,所以我们可以说这个对象很有可能是内存泄露了。