美文网首页
Lua的hook机制及内存泄漏检测

Lua的hook机制及内存泄漏检测

作者: XavierCHN | 来源:发表于2017-06-23 15:55 被阅读0次

    最近突然有了对lua内存泄漏进行检测的需求,去研究了一下lua的说明书,发现lua的hook机制可以很好地满足要求。

    1 hook机制

    lua的hook属于debug库,可以在你的程序触发了某些事件的时候,调用你所注册的一个函数。
    可以触发hook函数的事件有四种:

    1. call事件: lua调用了一个函数的时候
    2. return事件:lua的函数返回了
    3. line事件:当lua开始执行新的一行代码
    4. count事件:在指定的数字后执行?
      lua在调用hook函数的时候,将会带有一个参数,一个字符串来表示生成这次调用的类型,也就是"call", "return", "line", or "count"中的一种。特殊的是,对于line事件,他还会带第二个参数,行号。 当然,我们可以用debug.getinfo来获得hook中的更多信息。
      注册一个hook需要使用debug.sethook函数,带两个或者三个参数,第一个是hook的回调函数,也就是事件触发的时候需要调用的函数,第二个参数是一个用来标识我们需要监听的函数类型的字符串,还有一个可选的参数标识调用的频率。
      第二个参数,可以是c´,r´, or `l´来分别代表四个事件。
      如果sethook函数没有任何参数,就代表停用hook。

    2 内存检测

    核心在于

    1. collectgabage("count")将会返回当前所占用的内存,并进行一次GC
    2. debug.getinfo() 函数可以在调用的时候获取行号

    使用方法:
    将代码放到你的文件夹中,在addon_game_mode.lua或者你的入口处的文件中require对应的文件,之后你可以使用utilsMemoryLeakDetector:ShowRecord(count)函数,或者使用debug_dump_lua_memory_detail的控制台指令来查看当前的状态

    local memory_state = {} -- 储存所有的内存调用
    local current_memory = 0 -- 储存总内存状态
    
    local function recordAlloc(event, line_no)
        local memory_increased = collectgarbage("count") - current_memory
        if (memory_increased < 1e-6) then return end
    
        local info = debug.getinfo(2, "S").source
        info = string.format("%s@%s", info, line_no - 1)
    
        local item = memory_state[info]
        if not item then
            memory_state[info] = {info, 1, memory_increased}
        else
            item[2] = item[2] + 1
            item[3] = item[3] + memory_increased
        end
        current_memory = collectgarbage("count")
    end
    
    utilsMemoryLeakDetector = {}
    
    function utilsMemoryLeakDetector:StartRecord()
        if debug.gethook() then
            self:StopRecord()
            return
        end
    
        memory_state = {}
        current_memory = collectgarbage("count")
        debug.sethook(recordAlloc, "l")
    end
    
    function utilsMemoryLeakDetector:ShowRecord(count)
        if not memory_state then return end
        local sorted = {}
    
        for k, v in pairs(memory_state) do
            table.insert(sorted, v)
        end
    
        table.sort(sorted, function(a, b) return a[3] > b[3] end)
    
        for i = 1, count do
            local v = sorted[i]
            print(string.format("MemoryDump [MEM: %sK] [COUNT: %s ] [AVG: %s k] %s:", v[3], v[2], v[3] / v[2], v[1]))
        end
    end
    
    function utilsMemoryLeakDetector:EndRecord()
        debug.sethook()
    end
    
    utilsMemoryLeakDetector:StartRecord()
    
    if IsInToolsMode() then
        Convars:RegisterCommand("debug_dump_lua_memory_detail",function(_, top_count)
            count = tonumber(top_count) or 30
            utilsMemoryLeakDetector:ShowRecord(count)
        end,"Dump lua usage",FCVAR_CHEAT)
    end
    

    相关文章

      网友评论

          本文标题:Lua的hook机制及内存泄漏检测

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