遊戲 Lag 白皮書 › L10 記憶體
記憶體洩漏 Memory leak
原因 ID mem-leak · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
在含圖解與實驗的完整版中開啟卡片 →
沒有釋放的記憶體一點一點累積,幾天後演變成 GC 暴增、swap 或處理程序被強制終止。
為什麼 已登出角色的資料、事件處理常式(event handler)沒有被釋放 → 於是 可用記憶體在幾天內逐漸減少 → 畫面上 維護剛結束時一切正常,之後一天比一天 lag,最後伺服器當機
- 症狀
- 慢動作, 定格, 斷線
- 因素
- 停滯
- 誰會遇到
- 整個伺服器
- 何時
- 開越久越嚴重, 晚間尖峰時段
- 負責單位
- 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
- 遊戲開發團隊要做的事
- 分析 heap dump、進行長時間負載測試。
- 基礎設施團隊要做的事
- 監控各處理程序記憶體用量的趨勢並設定警示。
- 圖表上
- 緩慢爬升 · 處理程序記憶體(RSS)、GC 後的 heap
- 查看位置
- 以數天為單位觀察遊戲伺服器處理程序的記憶體(pidstat -r 的 RSS);有 GC 的伺服器則看 GC 剛結束時剩下的 heap。Java 看 -Xlog:gc 行中 GC 前後用量裡的 GC 後數值;.NET 看 dotnet-counters 的 GC 後 heap 大小(.NET 9 以後為 dotnet.gc.last_collection.heap.size,8 以下為 GC Heap Size)
- 符合的跡象
- GC 剛結束時剩下的 heap(基線)在重新啟動後每天上升,人少的凌晨也不會降下來
- 不符合的跡象
- heap 基線持平、只有 RSS 上升時,是碎片化(mem-fragment)或原生記憶體(native memory)的問題。隨人數起伏時是正常用量
- 確認方式
- 用基礎設施工具確認(不需要遊戲程式碼)
- 深入了解
- 如果每週定期維護都會重新啟動,洩漏就會被掩蓋,很久都不會被發現。常見的情況是某次維護延後,或活動讓人數增加時,問題才突然浮現。
出處
- Troubleshoot Memory Leaks Oracle
執行越來越慢時要懷疑洩漏,最後記憶體耗盡而異常終止。分析洩漏的關鍵資料是 heap dump - Debug a memory leak in .NET .NET
即使有 GC,持續參考不再需要的物件也會造成洩漏,導致效能下降與 OutOfMemoryException。確認記憶體趨勢並分析 dump - Garbage Collector Implementation Oracle
-Xlog:gc 行的格式為「GC 前用量->GC 後用量(heap 大小)」 - 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(實際位於 RAM 中的記憶體)與分頁錯誤
相關原因
同一層:L10 記憶體
同一症狀(慢動作)在其他層的原因
查看含圖解與實驗的完整版卡片