您现在的位置是:网站首页 -> 后端开发 文章内容
检测Lua中临时对象造成的内存增长-itarticl.cc-IT技术类文章记录&分享
发布时间: 8年前【后端开发】 128人已围观【返回】
做这事的起因是做服务器压测时发现lua内存每秒涨10M,涨到很高的时候才能被gc降下来,得想办法解决了。之前的《Unity3D游戏优化之Lua的内存》讲过如何查找gc不掉的内存,和windows上用umdh查分配栈找到slua里vector3类型转换造成的临时内存增长。这次说一下通用性查找可被gc掉的内存的方法,比较两个时间的堆快照的对此无效,因为临时对象在俩堆里都没引用。
创建临时对象,比如临时表、临时闭包,向table里加key value,都会使lua虚拟机内存增加,虽然可被gc掉但会造成更频繁的gc,gc速度没分配速度快的话进程容易挂。问题就是如何自动化的找到分配临时对象内存的lua代码,造成内存增长的情况很多怎么找呢,在lua c代码里realloc的时候打印当前代码行?想了2天之后发现方法很简单,50行代码就搞定了,多跟别人扯扯淡还是很有用的,活跃自己的思路,你可以当作智力题想想再往下看。
lua有个hook机制,详见debug.sethook() or Programming in Lua : 23.2,lua profiler就是hook到function call & return事件做计时的,为了降低测量对时间精度的影响实现在了c里。hook机制里还有一个是line事件,每要执行新的一行都会回调,可以用来写lua debugger。上面的内存问题可以转化为找所有使lua虚拟机内存增长的代码行,每次line事件回调时比较内存是否增长了,涨了就记下代码行,累加次数和内存量,一段时间之后排序输出报告即可。黑白代码如下,您稍微改改就能运行
-- 每一行代码的内存增长次数、大小k
local memStat = { }
local currentMem = 0
-- 是否按行统计,否则只按文件统计
local statLine = true
local function RecordAlloc(event, lineNo)
local memInc = collectgarbage("count") - currentMem
-- 没涨内存就不统计
if (memInc <= 1e-6) then return end
-- 2nd from stack top is the func hooked
local s = debug.getinfo(2, 'S').source
if statLine then
s = string.format("%s__%d", s, lineNo - 1)
end
local item = memStat[s]
if (not item) then
memStat[s] = { s, 1, memInc }
else
item[2] = item[2] + 1
item[3] = item[3] + memInc
end
-- 最后再读一次内存,忽略本次统计引起的增长
currentMem = collectgarbage("count")
end
function SC_MemLeakDetector.SC_StartRecordAlloc(igoreLine)
if (debug.gethook()) then
SC_MemLeakDetector.SC_StopRecordAllocAndDumpStat()
return
end
memStat = { }
currentMem = collectgarbage("count")
statLine = not igoreLine
-- hook到每行执行
debug.sethook(RecordAlloc, 'l')
end
function SC_MemLeakDetector.SC_StopRecordAllocAndDumpStat(filename)
debug.sethook()
if (not memStat) then return end
local sorted = { }
for k, v in pairs(memStat) do
table.insert(sorted, v)
end
-- 按内存排序
table.sort(sorted, function(a, b) return a[3] > b[3] end)
filename = filename or "memAlloc.csv"
local file = io.open(filename, "w")
if (not file) then
logw.error("can't open file:", filename)
return
end
file:write("fileLine, count, mem K, avg K\n")
for k, v in ipairs(sorted) do
file:write(string.format("%s, %d, %f, %f\n", v[1], v[2], v[3], v[3] / v[2]))
end
file:close()
memStat = nil
end
立即就能找到热点,具体原因就不好意思说了,反正是创建临时表的问题。
服务器客户端(unity+slua)都能用,对性能有一定影响,帧率能降低几倍
发布时间: 8年前【后端开发】128人已围观【返回】【回到顶端】
很赞哦! (1)
相关文章
点击排行

站长推荐

猜你喜欢
站点信息
- 建站时间:2016-04-01
- 文章统计:728条
- 文章评论:82条
- QQ群二维码:扫描二维码,互相交流
