You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中JSON序列化大尺寸多维数组的性能问题咨询

Unity地形Splatmap序列化性能问题排查

我正在Unity中学习数据序列化,尝试保存随时间变化的地形瓦片splatmaps/alphamaps。这些splatmaps/alphamaps尺寸为5125123,单份就包含超过50万个浮点数据。目前序列化16份这类数据时,耗时高达50秒,生成的JSON文件大小达到246MB。我用Newtonsoft配合自定义转换器实现,输出结果看似正常,但不确定这个耗时和文件体积是否合理,也不清楚代码有没有问题,希望能得到排查帮助。

现有序列化代码

private void SaveTerrainCellData(string SaveName)
{
    string saveName = $"{SaveName} - TerrainCellData";
    string filePath = (Application.persistentDataPath + "/" + saveName + ".json");
    string lines = null;
    //Debug.Log(Application.persistentDataPath);

    // Use custom converters
    var settings = new JsonSerializerSettings
    {
        Converters = new JsonConverter[] { new Vector3Converter(), new StringEnumConverter() },
        Formatting = Formatting.Indented
    };

    foreach (TerrainCellData data in this.terrainCellsData)
    {
        lines += JsonConvert.SerializeObject(data, settings);
    }

    File.WriteAllText(filePath, lines);
    //await Task.Yield();
}

数据结构定义

public struct TerrainCellData
{
    [SerializeField] public string TerrainName; 

    [Header("--- Weather ---")]
    public Weather Weather;
    public float MinutesSinceWeatherChange;

    [Header("--- Simulation ---")]
    public Biome Biome;
    public float WaterLevel;
    public float SunLevel;
    public int DirtPatchCount;
    public int GrassPatchCount;

    public List<Vector3> DirtAlphaMapGridID;
    public List<Vector3> GrassAlphaMapGridID;
    public Vector3 TrailingGrassPatch;
    public Vector3 TrailingDirtPatch;

    public Dictionary<ObjectName, Vector3> TrailingPlants;
    public int TrailingGrassPlantIndex;

    public float[,,] OriginalSplatmapData;
    public Dictionary<Vector3, float[,,]> AlphaMapGrid;
    public float[,,] AlphaMap;

    public void WriteData(string TerrainName,
                           Weather Weather, 
                           float MinutesSinceWeatherChange, 
                           Biome Biome, 
                           float WaterLevel, 
                           float SunLevel, 
                           int DirtPatchCount, 
                           int GrassPatchCount, 
                           List<Vector3> DirtAlphaMapGridID, 
                           List<Vector3> GrassAlphaMapGridID,
                           Vector3 TrailingGrassPatch,
                           Vector3 TrailingDirtPatch,
                           Dictionary<ObjectName, Vector3> TrailingPlants,
                           int TrailingGrassPlantIndex,
                           float[,,] OriginalSplatmapData,
                           Dictionary<Vector3, float[,,]> AlphaMapGrid,
                           float[,,] AlphaMap)
    {
        this.TerrainName = TerrainName;
        this.Weather = Weather;
        this.MinutesSinceWeatherChange = MinutesSinceWeatherChange;
        this.Biome = Biome;
        this.WaterLevel = WaterLevel;
        this.SunLevel = SunLevel;
        this.DirtPatchCount = DirtPatchCount;
        this.GrassPatchCount = GrassPatchCount;
        this.DirtAlphaMapGridID = DirtAlphaMapGridID;
        this.GrassAlphaMapGridID = GrassAlphaMapGridID;
        this.TrailingGrassPatch = TrailingGrassPatch;
        this.TrailingDirtPatch = TrailingDirtPatch;
        this.TrailingPlants = TrailingPlants;
        this.TrailingGrassPlantIndex = TrailingGrassPlantIndex;
        this.OriginalSplatmapData = OriginalSplatmapData;
        this.AlphaMapGrid = AlphaMapGrid;
        this.AlphaMap = AlphaMap;
    }
}

问题排查与优化方向

  • 修复字符串拼接的性能浪费:当前用lines +=拼接序列化结果,每次拼接都会生成新字符串,产生大量GC开销。改用StringBuilder替代:

    StringBuilder sb = new StringBuilder();
    foreach (TerrainCellData data in this.terrainCellsData)
    {
        sb.Append(JsonConvert.SerializeObject(data, settings));
    }
    File.WriteAllText(filePath, sb.ToString());
    
  • 替换JSON为二进制序列化:JSON是文本格式,存储大量浮点数据天生低效。可以改用:

    • Unity内置的二进制序列化方案(注意版本兼容性)
    • MessagePack这类高效二进制序列化库
    • 自定义二进制写入:直接将浮点数组转为字节数组写入,跳过文本转换
  • 关闭JSON缩进格式:Formatting.Indented会增加文件体积和序列化时间,若不需要人工查看,改为Formatting.None可显著提升速度并减小文件大小。

  • 清理冗余数据:检查TerrainCellData中的重复或可推导数据,比如OriginalSplatmapData是否需要完整保存;Dictionary<Vector3, float[,,]>中的Vector3键可转为紧凑格式(如x,y,z字符串或整数哈希),减少序列化开销。

  • 异步执行避免主线程卡顿:将序列化和文件写入改为异步操作,避免阻塞游戏主线程:

    private async Task SaveTerrainCellDataAsync(string SaveName)
    {
        string saveName = $"{SaveName} - TerrainCellData";
        string filePath = Path.Combine(Application.persistentDataPath, saveName + ".json");
        StringBuilder sb = new StringBuilder();
    
        var settings = new JsonSerializerSettings
        {
            Converters = new JsonConverter[] { new Vector3Converter(), new StringEnumConverter() },
            Formatting = Formatting.None
        };
    
        foreach (TerrainCellData data in this.terrainCellsData)
        {
            sb.Append(JsonConvert.SerializeObject(data, settings));
        }
    
        await File.WriteAllTextAsync(filePath, sb.ToString());
    }
    

内容的提问来源于stack exchange,提问作者MrSig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 14:53:17