转自http://blog.csdn.net/xocoder/article/details/42685685

由于目前正在负责的项目是一个二次开发项目,而且留给我们的代码质量实在让人无力吐槽,所以遇到了不少大大小小的坑,好在慢慢都淌过去了。最近就遇到了一个内存泄漏的问题,泄漏发生在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 =
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 +
end
end
return false
end function _G.findObjectInGlobal(obj)
findedObjMap = {}
setmetatable(findedObjMap, {__mode = "k"})
_G.findObject(obj, _G)
end

Lua内存泄漏应对方法[转]的更多相关文章

  1. [Lua]内存泄漏与垃圾回收

    参考链接: http://colen.iteye.com/blog/578146 一.内存泄漏的检测 Lua的垃圾回收是自动进行的,但是我们可以collectgarbage方法进行手动回收.colle ...

  2. iOS AFNetworking内存泄漏处理方法

    iOS AFN内存泄漏处理方法 细心的你是否也发现AFN的内存泄漏的问题了呢. 在这里给大家提供一个解决AFN内存泄漏的方法. 单例解决AFN内存泄漏 + (AFHTTPSessionManager ...

  3. C++程序内存泄漏检测方法

    一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成“统一”的标准.而在W ...

  4. VS2005内存泄漏检测方法[转载]

    一.非MFC程序可以用以下方法检测内存泄露: 1. 程序开始包含如下定义: #ifdef _DEBUG #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __ ...

  5. Android内存管理(5)*官方教程:Logcat内存日志各字段含义,查看当前内存快照,跟踪记录内存分配,用adb查看内存情况时各行列的含义,捕获内存快照的3种方法,如何让程序暴漏内存泄漏的方法

    Investigating Your RAM Usage In this document Interpreting Log Messages                 内存分析日志中各消息的含 ...

  6. Chrome JS内存泄漏排查方法(Chrome Profiles)

     原文网址:http://blog.csdn.net/kaitiren/article/details/19974269 JS内存泄漏排查方法(Chrome Profiles)   Google Ch ...

  7. 关于 Lua 内存泄漏的检测

    前一阵开始和同事一起优化内存,首先是优化 Lua 内存,因为发现每次战斗完后 Lua 内存非常大,从 3M 左右在经过了10次左右的战斗后,会暴增到近 100M,很明显是有内存泄漏.      然后我 ...

  8. VS2005 检测内存泄漏的方法(转载)

    一.非MFC程序可以用以下方法检测内存泄露: 1.程序开始包含如下定义: #ifdef _DEBUG #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __F ...

  9. C++程序在Windows平台上各种定位内存泄漏的方法,并对比了它们的优缺点

    一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成“统一”的标准.而在W ...

随机推荐

  1. [AngularJS + RxJS] Search with RxJS

    When doing search function, you always need to consider about the concurrent requests. AEvent ----(6 ...

  2. Linux gdb调试入门

    没有使用过gdb调试过程序的觉得gdb是个很神奇的东东,如果你使用它调试一次保证你想忘记它都难,下面看看它的庐山真面目吧! GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具. ...

  3. 再说重写IHttpHandler,实现前后端分离

    aspx页面第一次加载时,HttpHandler 里面是如何编译指定页面的呢?Framework提供了编译页面的API如下: BuildManager.CreateInstanceFromVirtua ...

  4. android*API19

     android android.accessibilityservice android.accounts android.animation android.app android.app.adm ...

  5. tableview 分割线置最左边的解决方法

    首先在viewDidLoad方法加入以下代码: if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) { [se ...

  6. [OC笔记] static 关键字

    在变量声明前加上static关键字,可以使局部变量保留多次方法调用所得到的值.当多个方法对一个静态变量进行操作时,多个方法共享同一个静态变量的值.

  7. IIS报500.0错误

    IIS安全里面配置:Everyone.IUSR.IIS_IUSRS 参考地址:http://blog.chinaunix.net/uid-21375345-id-3213631.html

  8. 利用MiddleGen-hibernate-r5生成hbm文件及POJO文件

    1       先决条件 1.1    已安装JDK(版本1.5以上)并配置环境变量 到http://java.sun.com上下载JDK,配置环境变量(我的电脑右键->属性->高级-&g ...

  9. C++中的类指针

    代码: #include <iostream> #include <string> #include <cstdio> using namespace std; c ...

  10. iframe和response.sendRedirect使用的问题

    一.iframe下使用response.sendRedirect的问题 一般使用filter过滤用户是否登录,如果用户没有登陆则转向登陆页面,这时候可以使用response.sendRedirect( ...