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

Unity 6中源生成式System.Text.Json仍频繁调用GetTypeInfo导致性能不及Newtonsoft.Json的问题排查

Unity 6中源生成式System.Text.Json仍频繁调用GetTypeInfo导致性能不及Newtonsoft.Json的问题排查

我特别理解你的困惑——明明冲着System.Text.Json源生成的AOT友好、低内存、高性能去的,结果反序列化前的初始化耗时反而比Newtonsoft还高,完全没达到预期,这肯定让人头疼。结合你贴的代码和描述,我来帮你拆解下问题:

一、为什么会频繁调用GetTypeInfo?

这绝对不是源生成的正常表现,说明你的序列化流程没有完全走预生成的代码路径,部分类型的处理fallback到了反射模式。

源生成的核心价值就是预先生成所有需要的序列化/反序列化代码,彻底绕过反射;一旦有未被标记为[JsonSerializable]的类型(包括嵌套类型、泛型参数、接口实现等)出现在你的序列化树中,System.Text.Json就会自动切换到反射兜底逻辑,而反射路径必然会频繁调用GetTypeInfo来读取类型元数据,这就是你看到300ms耗时的根源。

二、具体排查&修复步骤

1. 全面检查所有涉及的序列化类型

你已经标记了MainConcreteClass、ConcreteClass2、ConcreteClass3,但要仔细核对以下场景:

  • 嵌套类型/泛型参数:如果MainConcreteClass里有public List<ConcreteClass4> Items,或者public Dictionary<string, SubNestedClass> Config这类字段,那ConcreteClass4、SubNestedClass甚至List<ConcreteClass4>都需要被添加[JsonSerializable]标记(.NET 7+可以自动处理泛型容器的参数类型,但Unity的环境可能需要显式声明)。
  • 接口/多态类型:如果MainConcreteClass里有接口类型的属性,比如public IBaseClass MyData,哪怕你标记了所有接口的实现类,也需要给IBaseClass添加[JsonSerializable],同时在JsonSourceGenerationOptions里配置多态支持(比如添加PolymorphismOptions = new JsonPolymorphismOptions { TypeInfoResolver = ... }),否则接口类型的处理会触发反射。
  • 值类型/特殊类型:比如自定义结构体、枚举,是否也需要标记?大部分基础值类型不需要,但如果是你自定义的复杂值类型,最好也加上[JsonSerializable]。

2. 确认源生成代码是否正确生成

在Unity项目里,检查Library/ScriptAssemblies或者项目根目录的Generated文件夹(取决于你的Unity版本),找AppJsonContext.g.cs这个自动生成的文件:

  • 如果这个文件不存在,说明源生成器根本没运行——大概率是项目有编译错误,或者Unity的源生成配置有问题,先解决所有编译报错再试。
  • 如果文件存在,打开看里面的代码:正常的源生成代码会有针对每个标记类型的JsonTypeInfo实现,比如针对MainConcreteClass,会有类似下面的预生成方法,完全没有反射相关的逻辑:
private static JsonTypeInfo<MainConcreteClass> Create_MainConcreteClass(JsonSerializerOptions options)
{
    // 预生成的序列化/反序列化逻辑,直接操作字段/属性,无反射
}

如果生成的代码里有GetTypeInfo或者Reflection相关的调用,说明源生成没有正确处理某些类型,触发了兜底逻辑。

3. 检查Unity的项目配置

Unity对Roslyn源生成的支持需要几个关键配置:

  • 确认Player Settings > Other Settings > Configuration > .NET API Compatibility Level设置为.NET 6或更高(Unity 6默认应该是这个,但手动核对下,旧版本的.NET兼容级别不支持完整的源生成)。
  • 确认Scripting Runtime Version设置为.NET Framework(不是旧的Mono Runtime),Mono对源生成的支持有限。
  • 关闭任何可能干扰源生成的第三方插件:有些代码压缩、混淆插件可能会误删源生成的代码,或者阻止源生成器运行,临时禁用这类插件测试下。

4. 验证源生成上下文的使用是否正确

你的代码里JsonSerializer.Deserialize(response.Data, AppJsonContext.Default.MainConcreteClass)看起来是对的,但要排除以下坑:

  • 不要在任何地方修改AppJsonContext.Default的配置:比如如果有人写了AppJsonContext.Default.Options = new JsonSerializerOptions(),这会直接破坏源生成的预配置,触发反射路径。
  • 不要混用源生成上下文和手动创建的JsonSerializerOptions:比如不要调用JsonSerializer.Deserialize(response.Data, typeof(MainConcreteClass), AppJsonContext.Default.Options),这会绕过预生成的类型信息,走反射。

三、IL2CPP环境的额外优化

因为你用的是Unity的IL2CPP AOT编译,还有两个点要注意:

  1. 在Player Settings > Other Settings > Optimization里开启Optimize Generated Code,这会让IL2CPP更好地优化源生成的代码,进一步提升性能。
  2. 如果遇到类型被IL2CPP裁剪的问题(比如某些嵌套类型被误删),可以在项目根目录添加link.xml文件,显式保留序列化相关的类型:
<linker>
  <assembly fullname="YourAssemblyName">
    <type fullname="MainConcreteClass" preserve="all" />
    <type fullname="ConcreteClass2" preserve="all" />
    <!-- 其他需要保留的类型 -->
  </assembly>
</linker>

最后验证

当你调整完所有配置后,重新编译项目,再跑性能分析:

  • GetTypeInfo的调用应该几乎消失(最多只有极少量的初始化调用,不会每个属性都触发)。
  • 反序列化的总耗时应该降到几十毫秒级别,内存占用比Newtonsoft低很多,这才是源生成该有的表现。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 07:08:06