关闭

Lua内存泄漏应对方法

8297人阅读 评论(2) 收藏 举报
分类:

由于目前正在负责的项目是一个二次开发项目,而且留给我们的代码质量实在让人无力吐槽,所以遇到了不少大大小小的坑,好在慢慢都淌过去了。最近就遇到了一个内存泄漏的问题,泄漏发生在lua里,项目代码里以前的开发团队留下了检测泄漏的代码,但也仅限于此。由于代码量庞大,所以想从逻辑上梳理清楚哪里的引用没干掉导致了内存泄漏几乎就是大海捞针。好在解决的过程比较顺利,这篇文章就来谈一谈Lua中如何解决内存泄漏的问题。


至于如何发现内存泄漏,也简单说一下,如果是陌生代码,或者虽然是你的,但你也懒得猜哪里泄漏了,那么请参考云风的泄漏检查工具:http://blog.codingnow.com/2012/12/lua_snapshot.html


如果代码的大体逻辑比较熟悉,则可以使用弱引用表来检查是否存在泄漏。通常产生泄漏的都是一些被反复创建的类型,例如游戏里的怪物(打死了就刷一个新的)、玩家(有人登录就要创建一个新的玩家对象),这些东西由于在程序运行周期里反复地创建、销毁,所以一旦有销毁不干净的情况,就容易导致明显的内存泄漏。那么探查这些对象是否存在泄漏,就有一个较为简单的办法,即:弱引用表。(如果你不知道什么是弱引用,请点击这里)。

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


说完了发现泄漏的方法,接下来轮到如何解决。其实我本来也想尝试一下云大的snapshot,奈何这个项目用的是luajit,莫名其妙地不能require,时间紧迫,无法研究,只好作罢,另寻他法。不料一顿google下来除了snapshot之外几乎没有一个像样的解决方案。情急之下,只好研究原理,自己动手,下面请看干货:

既然内存泄漏一定有引用没清,那么基于lua的特性,这个引用一定存在于_G下面的某个table或者function的upvalue中(想不明白这个的同学请想明白再往下看),既然第一步的方法可以定位泄漏,而且还可以得到泄漏对象的引用,那么事情就好办多了。无非就是得到引用之后遍历_G,找到这个引用,并且把层级列出来,方便知道这个东西到底在哪里,想解决就好办的多了。实现方法就不多说了,看代码最直接。下面代码中,调用findObjectInGlobal(泄漏对象的引用),即可找到一切非局部变量的归属关系。


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"})
    _G.findObject(obj, _G)
end


1
0

猜你在找
深度学习基础与TensorFlow实践
【在线峰会】前端开发重点难点技术剖析与创新实践
【在线峰会】一天掌握物联网全栈开发之道
【在线峰会】如何高质高效的进行Android技术开发
机器学习40天精英计划
Python数据挖掘与分析速成班
微信小程序开发实战
JFinal极速开发企业实战
备战2017软考 系统集成项目管理工程师 学习套餐
Python大型网络爬虫项目开发实战(全套)
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:308207次
    • 积分:3403
    • 等级:
    • 排名:第9257名
    • 原创:73篇
    • 转载:36篇
    • 译文:0篇
    • 评论:75条
    最新评论
    好站链接
    尤龙同学的代码与诗歌