游戏卡顿白皮书 › L10 内存
内存泄漏 Memory leak
原因 ID mem-leak · 主责 研发团队·服务器开发 · 配合 运维团队·系统运维
在含图示和实验的完整版中打开此卡片 →
没有释放的内存一点点累积,几天后引发 GC 失控、swap 或进程被强制终止。
起因 已下线角色的数据、事件处理函数没有释放 → 结果 空闲内存在几天内持续减少 → 画面表现 维护结束后正常,越往后越卡,最终服务器宕机
- 症状
- 慢动作, 卡住, 掉线
- 因素
- 停顿
- 谁会遇到
- 全服
- 何时出现
- 开得越久越严重, 晚高峰
- 负责方
- 主责 研发团队·服务器开发 · 配合 运维团队·系统运维
- 研发团队要做的事
- 分析堆 dump,长时间压测。
- 运维团队要做的事
- 监控各进程内存占用的趋势并设置告警。
- 监控图上
- 缓慢爬升 · 进程内存(RSS)、GC 后的堆
- 查看位置
- 以天为单位看游戏服务器进程的内存(pidstat -r 的 RSS);带 GC 的服务器看 GC 刚结束时剩余的堆。Java 看 -Xlog:gc 行里 GC 前后占用量中的 GC 后数值,.NET 看 dotnet-counters 的 GC 后堆大小(.NET 9 起为 dotnet.gc.last_collection.heap.size,8 及以下为 GC Heap Size)
- 确认依据
- GC 后剩余的堆(谷底基线)在重启后逐日抬高,凌晨人少时也不回落
- 排除依据
- 堆的谷底基线平稳、只有 RSS 上涨,看“内存碎片”(mem-fragment)或原生内存。随人数起伏则是正常占用
- 确认手段
- 运维工具即可确认(无需游戏代码)
- 深入了解
- 每周例行维护都会重启,泄漏因此被掩盖,很长时间都发现不了。往往在某次维护推迟、或活动带来人数增加时突然暴露。
出处
- Troubleshoot Memory Leaks Oracle
运行越来越慢时应怀疑泄漏,最终内存耗尽而异常退出。分析泄漏的关键材料是堆 dump - Debug a memory leak in .NET .NET
即使有 GC,一直引用不再需要的对象也会泄漏,导致性能下降和 OutOfMemoryException。做法是查看内存趋势并分析 dump - Garbage Collector Implementation Oracle
-Xlog:gc 行的格式为“GC 前占用->GC 后占用(堆大小)” - dotnet-counters diagnostic tool .NET
.NET 9 起显示为 dotnet.gc.last_collection.heap.size,.NET 8 及以下显示为 GC Heap Size - pidstat(1) — Linux manual page sysstat
-r:各进程的 RSS(实际驻留在物理内存中的部分)和缺页(page fault)
相关原因
同一层:L10 内存
其他层中同样导致“慢动作”的原因
查看含图示和实验的原卡片