한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

遊戲 Lag 白皮書 › L1 用戶端遊戲程式

用戶端垃圾回收 Client GC (Unity C#, Unreal, Lua)

原因 ID cg-gc · 主要負責 遊戲開發團隊(用戶端開發)

在含圖解與實驗的完整版中開啟卡片 →

回收用過即丟的記憶體(垃圾)期間,整個遊戲會暫停。特徵是以規律的間隔出現卡頓。

為什麼 每個畫格都建立再丟棄暫時性的字串、陣列、List → 於是 垃圾累積起來後,GC 暫停主執行緒進行回收 → 畫面上 每隔幾秒~幾十秒規律地出現卡頓

症狀
卡頓, 定格
因素
停滯
誰會遇到
只有我
何時
固定週期, 人潮湧入時
負責單位
主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事
減少記憶體配置(避免字串串接、LINQ、lambda 捕捉)、使用物件池、開啟漸進式 GC(Unity 2020 以後為預設值)、趁讀取畫面這類暫停也無妨的時機先執行 GC。
數值參考
一般每次數 ms~100ms,低階手機或記憶體用量大的遊戲會更久(實驗中約 150~170ms)。Unity 的 GC 每次執行都會檢查整個 heap,所以遊戲使用中的記憶體越多,暫停就越久。
圖表上
固定週期飆高 · 畫格時間、GC 執行時間點
查看位置
在開發版本中查看 Unity Profiler 的 GC.Collect、GC.Alloc 標記。Unreal 則看 stat GC 與 stat Hitches(把超過 t.HitchFrameTimeThreshold 所設時間的畫格記進 log)
符合的跡象
每個飆高的畫格都有 GC.Collect 區段,長度與飆高的長度相近,間隔為幾秒~幾十秒且規律。在人多的地方,每個畫格的 GC.Alloc 會增加
不符合的跡象
飆高的畫格沒有 GC 區段時,是「主執行緒同步載入、著色器編譯」或「大量角色同畫面的渲染負載」
確認方式
需要遊戲伺服器/用戶端的 log 與指標
深入了解
在 Unity 這類使用 C# 的用戶端很常見。主要元凶是每個畫格都重新產生戰鬥紀錄字串、傷害數字、UI 文字的程式碼。如果只在人多的地方卡頓,代表有程式碼產生的垃圾會隨人數成比例增加。漸進式 GC 會把回收工作分散到每個畫格各做一點(Unity 預設 3ms),但產生垃圾的速度一旦快過回收速度,最後還是會一次暫停。Unreal Engine 也有自己的 GC,負責清理不再使用的遊戲物件;雖然依引擎版本與設定而不同,預設設定下約每 1 分鐘執行一次,有時會造成每隔 1 分鐘頓一下。遊戲規則用 Lua 等腳本撰寫的用戶端,該腳本的 GC 也會另外執行。

出處

  1. Garbage collection modes Unity
    漸進式 GC 為預設值,會分散到多個畫格回收;關閉時,檢查整個 heap 的期間主執行緒會暫停,可能長達數百 ms
  2. Scripting.GarbageCollector.CollectIncremental Unity
    漸進式 GC 每次使用的時間(時間片段)預設目標為 3ms(incrementalTimeSliceNanoseconds)
  3. Garbage Collection Settings in the Unreal Engine Project Settings Epic Games
    Unreal GC 依固定間隔(Time Between Purging Pending Kill Objects,單位為秒)執行的設定。這份文件沒有寫出預設值
  4. Profiler markers reference Unity
    GC.Collect:垃圾回收期間程式碼暫停的區段(不到 1ms~數百 ms);GC.Alloc:managed heap 配置
  5. Stat Commands in Unreal Engine Epic Games
    stat GC(垃圾回收統計)、stat Hitches(把超過 t.HitchFrameTimeThreshold 的畫格記錄到 log)

相關原因

同一層:L1 用戶端遊戲程式

同一症狀(卡頓)在其他層的原因

查看含圖解與實驗的完整版卡片