内存泄漏解决方案
snapshot是Lujit自带的库, 可以对所有lua对象做一次快照, 两次快照对比一下, 就知道第二次快照多了哪些对象, 在程序运行之初对所有引用的对象进行一次快照,程序结束之后再对所有引用的对象进行一次快照,然后对比两个快照便可以知道有没有内存泄漏:
以下是云风大大的测试用例:
local snapshot = require('snapshot');
-- 第一次快照
local S1 = snapshot();
local t = {};
-- 第二次快照
local S2 = snapshot();
for k,v in pairs(S2) do
if S1[k] == nil then
-- 打印多出来的对象
print(tostring(k), tostring(v));
end
end
但是有些情况下, 仍然不能解决问题, 例如当程序一直在运行, 并且是非线性的运行, 该如何检测内存泄漏呢?
有个办法是进行多次快照, 如果有些对象引用在多次快照中都存在, 则泄漏的可能性非常大。此时数据量也比较少, 容易看出问题来。
以下是代码提供:
local snapshot = require('snapshot');
local rr,ee = pcall(function()
-- 让内存释放一会, 以20秒以后的快照为基准快照
timer.setTimeout(20000, function()
-- 获取第一张快照, 这张快照里面的对象引用都是不计入计算的
local base = snapshot();
local count = {};
local S1 = nil;
local diff = {};
-- 弱引用, 弱引用表指向数据, 不影响数据的释放(数据被指向则不会释放)
setmetatable(diff, {__mode = 'k'});
setmetatable(count, {__mode = 'k'});
-- 每隔十秒进行一次快照
timer.setInterval(10000, function()
writeLog(-1,{'******************************快照开始, 并对比*****************************'})
-- 第二张快照
local S1 = snapshot();
for k,v in pairs(S1) do
-- 如果第一张快照中不存在该数据的引用, 历次快照的区别中也不存在这个数据的引用,则该数据是本次快照和上次快照之间生成的数据, 保存起来, 加入到历次快照的区别中, 并记重复次数为1
if diff[k] == nil and base[k] == nil then
writeLog(-1, {"出现次数:1", "key:"..tostring(k), "value:"..tostring(v)});
diff[k] = v;
-- 如果历次快照的差别中有该数据的引用, 则说明该数据的引用已经重复出现,打印出来
elseif diff[k] then
count[tostring(k)] = 1 + (count[tostring(k)] or 1)
writeLog(-1, {"出现次数:"..tostring(count[tostring(k)]), "key:"..tostring(k), "value:"..tostring(v)});
end
end
writeLog(-1,{'********************************快照对比结束*******************************'})
end)
end)
end)
查看内存泄漏的对象:(出现次数自己定, 重复次数越高, 内存泄漏的可能性越大, 可以直接定100次, 然后查找重复一百次以上的对象, 其中程序初始化时的对象引用已经基本排除了, 所以内存泄漏不严重的情况, 数据量应该是不多的)
grep -rn '出现次数:20' > 1
vim 1