完整课程入口:996 全套课程体系 | Lua 学习路径 | 幂尔框架 mirs.cn
某 996 客户端(cocos2d-x Lua 绑定)在线挂机两小时后,系统内存从 180M 涨到 320M,掉帧明显。Lua 侧占用用 collectgarbage("count") 测量,单位 KB;原生侧内存用 Xcode Instruments 的 Allocations 与 Android Profiler 对照。实测数据:Lua 侧 62M、原生纹理 180M,两条曲线独立增长,先查 Lua。
缓存表无上限。 界面模块给每个道具对象挂缓存:cache[item] = result,道具对象销毁后条目仍在。改成弱值表后,条目随对象回收自动清除:
-- 修复前:强引用,只进不出
local cache = {}
-- 修复后:value 弱引用
local cache = setmetatable({}, { __mode = "v" })
闭包抓住大对象。 GUI:addOnClickEvent(btn, function() use(panel) end) 的回调捕获整个面板 table,按钮注册进全局事件后面板永不释放。用 debug 库确认:
for i = 1, debug.getupvalue(fn, 0) and 0 or math.huge do end
local name, val = debug.getupvalue(fn, 1) -- 枚举捕获变量
循环内临时对象。 OnLoop 触发器每帧 string.format 与新建 table,GC 频率随之上升。用内存曲线对照:每次 GC 后回落的基线持续抬高,就是这类代码的指纹。
按收益排序执行三项修改:道具缓存改弱表(-31M);六个界面回调改为持有控件 id 而非面板 table,销毁时反注册(-18M);战斗循环内拼串改 table.concat、临时表提到循环外复用(-11M,GC 次数同步下降 40%)。两小时挂机实测:Lua 侧 62M 降到 8M,总内存 200M 降到 50M 左右,帧率波动从 ±12fps 收窄到 ±3fps。
测量工具链:Lua 侧 collectgarbage("count") 打点脚本、Instruments/Android Profiler 看原生侧、luac -l 确认热点函数的字节码指令数。排查口诀:先分 Lua 与原生两条曲线,再分缓存、闭包、临时对象三个来源,每改一处看一次曲线。这一套流程在同一项目的另外三个面板复用时,单面板排查时间从半天缩短到一小时。