博客 / 詳情

返回

如何解決ProtoBuf反序列化中GC高的問題

1)如何解決ProtoBuf反序列化中的GC高的問題
2)如何在編輯器中集成實時查看Mipmap使用層級工具


這是第455篇UWA技術知識分享的推送,精選了UWA社區的熱門話題,涵蓋了UWA問答、社區帖子等技術知識點,助力大家更全面地掌握和學習。

UWA社區主頁:community.uwa4d.com
UWA QQ羣:793972859

From UWA AI 問答

Q:有沒有比較好的解決ProtoBuf反序列化GC的方案?

A:在Unity項目中,使用ProtoBuf進行反序列化時產生的GC主要來源於兩方面:內存分配的臨時對象(如字符串、裝箱操作)和反射機制的低效調用。以下是針對這些問題的成熟且高效的解決方案。

1. 使用[Preserve]與強制AOT初始化避免反射GC
IL2CPP環境下,由於AOT編譯限制,ProtoBuf生成代碼中的泛型反射方法可能未被提前編譯,導致運行時嘗試動態調用而崩潰或觸發大量GC。為確保所有必要的反射初始化代碼被保留:

using Google.Protobuf.Reflection;
using UnityEngine.Scripting;

[Preserve]
private void ForceReflectionInitialization()
{
    // 顯式調用每個消息類型的ForceReflectionInitialization
    FileDescriptor.ForceReflectionInitialization<MyMessage1>();
    FileDescriptor.ForceReflectionInitialization<MyMessage2>();
    // 添加所有用到的消息類型
}

此方法無需調用,僅需存在即可被鏈接器保留。配合[Preserve]特性防止代碼剝離,可有效解決因AOT缺失導致的異常及性能損耗。

2. 避免字符串與值類型裝箱,實現0GC解析輔助
參考TMP文本優化思路,可對ProtoBuf解析過程中的輸出處理進行定製,減少中間對象分配。例如,在自定義的日誌系統或UI更新中直接複用StringBuilder寫入,而非通過ToString()創建新字符串。

  • 全局複用StringBuilder用於格式化輸出。
  • 對數字字段轉字符串時,採用無GC的NumberFormatter.NumberToString(ref char[] buffer, int value)方式,將結果寫入預分配字符數組。
  • 自定義IFormatter<T>實現,繞過裝箱操作,直接處理基本類型。

3. 使用原生字節訪問替代高開銷API
對於高頻解析場景(如網絡同步),考慮繞過完整反序列化流程,直接讀取字節流中的關鍵字段:

// 使用CodedInputStream直接讀取特定字段
var input = CodedInputStream.CreateInstance(data);
while (!input.IsAtEnd)
{
    var tag = input.ReadTag();
    switch (tag.FieldNumber)
    {
        case 1:
            int hp = input.ReadInt32();
            break;
        // 只解析必要字段
    }
}

這種方式跳過對象構建開銷,適用於只關心部分數據的輕量級更新。

4. 緩衝池管理Message實例
頻繁創建/銷燬ProtoBuf對象會加劇GC壓力。建議使用對象池緩存常用Message實例:

public class MessagePool<T> where T : IMessage, new()
{
    private static readonly Stack<T> _pool = new();

    public static T Get() => _pool.Count > 0 ? _pool.Pop() : new T();

    public static void Release(T msg) { _pool.Push(msg); }
}

結合Clear()重置狀態後複用,顯著降低內存分配頻率。

綜上,核心策略是:強制AOT初始化 + 禁止代碼剝離 + 複用緩衝區 + 裁剪不必要的反序列化流程。這些方法已在多個上線項目中驗證,能有效將ProtoBuf相關GC降至接近零。

分享鏈接:
https://www.uwa4d.com/main/uwa-shared.html?shareId=228136d0-9...


From 問答社區

Q:最近在優化貼圖內存,請問有沒有開源庫或者計算方法,可以檢測貼圖在屏幕上的佔比情況?

比如,一張1024的貼圖,如果渲染時一直使用很高層級的Mipmap,就説明其實不需要1024這麼高的分辨率。我記得有種工具還能通過顏色可視化,我主要想集成在編輯器裏面實時查看修改。

A:URP裏面編寫Mipmap工具可以參考以下鏈接:
Scene View Debug Modes in the Unity URP
A way to visualize mip levels

歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/6925280c682c7e5cd61bfb76

無論是社區裏開發者們的互助討論,還是AI基於知識沉澱的快速反饋,核心都是為了讓每一個技術難題都有解、每一次踩坑都有迴響。本期分享分別來自UWA AI問答和UWA問答社區,希望這些從真實開發場景中提煉的經驗,能直接幫你解決當下的技術卡點,也讓你在遇到同類問題時,能更高效地找到破局方向。

封面圖來源於網絡


今天的分享就到這裏。生有涯而知無涯,在漫漫的開發週期中,我們遇到的問題只是冰山一角,UWA社區願伴你同行,一起探索分享。歡迎更多的開發者加入UWA社區。

UWA官網:www.uwa4d.com
UWA社區:community.uwa4d.com
UWA學堂:edu.uwa4d.com
官方技術QQ羣:793972859

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.