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
相关产品推荐
相关产品推荐

