lua内存泄露检测原理


上次写了一个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脚本本身就是lua_state。
                           _G就是_G全局表。
                           Registry表可以用debug.getregistry获取。
                           global_mt可以用debug.getmetatable获取。
 

        所以我们就可以在脚本层次实现内存泄露的检测模块。

        在搜索时需要注意的几点:
        1、table 额外搜索metatable,若metatable中的__mode取值为”k"、"v"或者”kv"需特殊处理(补充中有说明)
        2. function 额外搜索 enviroment,也是一个table。额外搜索upvalues,这个可以是任何类型。
        3. 由于userdata在script层次不能被修改,所以搜搜他的metatable吧
        4. thread对象就是coroutine对象,在script中一般都不会创建多个coroutine,所以在脚本中没搜索它。若是需求的话,获取到它的线程函数,然后再按照第2步操作就可以了。
 
搜索流程图(_G表):
 
 
在检测泄露之前,先搜索一下所有的对象,保存好起始的内存状态,在程序执行之后执行几次GC操作,然后再进行一次搜索,对比两次的结果,多出来的那些就有可能是内存泄露了。
 
补充:

lua中有一种叫weak表的东东,它的metatable中的__mode被设置为“k","v"或者”kv",表示保存在它中的键或值或键值都是一种弱引用状态。
若一个对象的所有引用都是弱引用了,那么这个对象也会被GC回收掉,所以对应的weak表中此对象的入口就没有了。

所以我们可以用另外一种实现:就是把用户自己创建的资源对象统统都丢到weak表中,运行完程序后强制GC,然后去查看weak表,若表中还保存着那个对象,就意味着这个对象还有外部引用(相对弱引用我们就叫它为强引用吧),资源没有被GC掉,所以我们可以说这个对象很有可能是内存泄露了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值