游戏卡顿白皮书 › L10 内存
脚本引擎 GC 停顿 Scripting VM GC (Lua, etc.)
原因 ID mem-script-gc · 主责 研发团队·服务器开发
在含图示和实验的完整版中打开此卡片 →
即使是 C++ 服务器,如果任务、AI、技能用 Lua 等脚本来跑,脚本引擎执行 GC 期间,对应的场景也会停住。
起因 每个场景的脚本引擎在执行任务、AI、事件时大量创建临时对象 → 结果 脚本引擎的 GC 一次回收太多时,这个场景的 tick 停住 → 画面表现 只在特定场景、特定事件期间周期性地顿一下
- 症状
- 一卡一卡, 卡住
- 因素
- 停顿
- 谁会遇到
- 特定地点/分线
- 何时出现
- 人多的时候, 固定周期
- 负责方
- 主责 研发团队·服务器开发
- 研发团队要做的事
- 设置增量或分代 GC,每个 tick 推进一小步 GC,减少脚本中的临时对象。
- 数值参考
- 脚本堆涨到数百 MB 后,一次性集中回收(关闭增量回收,或分代模式下的完整回收)有时要花几十到几百 ms。
- 监控图上
- 周期性尖峰 · 各场景 tick 耗时、脚本引擎内存
- 查看位置
- 每个 tick 记录各场景的 tick 耗时和这个场景脚本引擎的内存占用(Lua 用 collectgarbage("count")),叠加在同一张图上对照
- 确认依据
- 脚本内存骤降的时刻(一次性集中回收)与这个场景的 tick 冲高重合,其他场景正常
- 排除依据
- 脚本内存没有变化却冲高,是这个场景的负载或锁。服务器上所有场景同时冲高,看“服务器 GC 全局停顿”(mem-gc)或“swap”(mem-swap)
- 确认手段
- 需要游戏服务器/客户端的日志和指标
出处
- Lua 5.4 Reference Manual Lua.org
增量模式把回收拆成小步,穿插在程序执行之间(步长设得太大就变成全局停顿);分代模式的 major 回收要遍历所有对象,属于全局停顿;collectgarbage("count") 返回 Lua 使用的内存总量(KB)
相关原因
同一层:L10 内存
其他层中同样导致“一卡一卡”的原因
查看含图示和实验的原卡片