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获取。
在搜索时需要注意的几点:
- table 额外搜索metatable,若metatable中的__mode取值为”k"、"v"或者”kv"需特殊处理(补充中有说明)
- function 额外搜索 enviroment,也是一个table。额外搜索upvalues,这个可以是任何类型。
- 由于userdata在script层次不能被修改,所以搜搜他的metatable吧
- 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
网友评论