美文网首页
Lua内存泄露检查

Lua内存泄露检查

作者: 尘尘飞 | 来源:发表于2020-02-14 21:27 被阅读0次

    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步操作就可以了。

    云风的泄漏检查工具

    工具链接:https://github.com/cloudwu/lua-snapshot
    对当前的 Lua State 做一个完整的快照,记录下所有 table thread userdata function 间的引用,在不同时间,对 Lua State 拍两个快照,相比较后,就很容易知道新增加的内存处于何处了。
    Lua 代码的运行过程本身会影响 State ,用 C 直接调用 lua API 来遍历 lua State ,影响要小的多。
    snapshot 的返回结果只是一张简单的 table ,每个 Lua 对象,都以指针(lightuserdata) 为 key 储存在表中;对应的 value 是一个 string 足够详细的描述了这个对象的引用关系。

    ref: http://blog.codingnow.com/2012/12/lua_snapshot.html

    使用弱引用表

    为了发现内存泄漏,我们可以创建一个全局的弱引用table,使其key为弱引用,然后在每次创建那些可能存在泄漏的对象的时候,都放入这个table,让其作为key,value通常我会用当前时间。由于弱引用的性质,如果其他引用都消失了,那么在弱引用table中对这个对象的引用也会消失(变成nil),反之,只要还有其它任何一个引用存在,这个弱引用表中对这个对象的引用就继续存在。依赖这个特性,当程序已经跑过释放对象的逻辑后,如果这个表中还存在有这个对象的引用,那么这个对象肯定就是泄漏了。
    既然内存泄漏一定有引用没清,那么基于lua的特性,这个引用一定存在于_G下面的某个table或者function的upvalue中。

    local findedObjMap = nil
    
    function _G.findObject(obj, findDest)
        if findDest == nil then
            return false
        end
        if findedObjMap[findDest] ~= nil then
            return false
        end
        findedObjMap[findDest] = true
        local destType = type(findDest)
        if destType == "table" then
            if findDest == _G.CMemoryDebug then
                return false
            end
            for key, value in pairs(findDest) do
                if key == obj or value == obj then
                    _info("Finded Object")
                    return true
                end
                if findObject(obj, key) == true then
                    _info("table key")
                    return true
                end
                if findObject(obj, value) == true then
                    _info("key:["..tostring(key).."]")
                    return true
                end
            end
        elseif destType == "function" then
            local uvIndex = 1
            while true do
                local name, value = debug.getupvalue(findDest, uvIndex)
                if name == nil then
                    break
                end
                if findObject(obj, value) == true then
                    _info("upvalue name:["..tostring(name).."]")
                    return true
                end
                uvIndex = uvIndex + 1
            end
        end
        return false
    end
    
    function _G.findObjectInGlobal(obj)
        findedObjMap = {}
        setmetatable(findedObjMap, {__mode = "k"}) --设置key弱引用
        _G.findObject(obj, _G)
    end
    

    ref: https://blog.csdn.net/xocoder/article/details/42685685

    待补充

    Unity Tolua集成工具 https://blog.csdn.net/tj134679258/article/details/71087630
    Lua实现,结果打印txt https://blog.csdn.net/damenhanter/article/details/71380666

    相关文章

      网友评论

          本文标题:Lua内存泄露检查

          本文链接:https://www.haomeiwen.com/subject/yifsfhtx.html