Json.NET 是不是缓存类型的序列化信息?
Posted
技术标签:
【中文标题】Json.NET 是不是缓存类型的序列化信息?【英文标题】:Does Json.NET cache types' serialization information?Json.NET 是否缓存类型的序列化信息? 【发布时间】:2016-02-07 01:34:27 【问题描述】:在 .NET 世界中,当涉及到对象序列化时,通常会在运行时检查对象的字段和属性。对这项工作使用反射通常很慢,并且在处理大量对象时是不可取的。另一种方法是使用 IL 发射或构建表达式树,它们提供了比反射显着的性能增益。后者是大多数现代图书馆在处理序列化时选择的。然而,在运行时构建和发布 IL 需要时间,而且只有在缓存这些信息并为相同类型的对象重用时才能收回投资。
在使用Json.NET的时候,我并不清楚使用了上面描述的哪种方法,如果确实使用了后者,是否使用了缓存。
例如,当我这样做时:
JsonConvert.SerializeObject(new Foo value = 1 );
Json.NET 是否构建 Foo 的成员访问信息并缓存以供以后重用?
【问题讨论】:
我没有给你一个明确的答案,但Json.NET 的来源在 github 上,它确实说“Json.NET 是一个流行的高性能 JSON 框架,用于 .NET” .如果您在源上快速搜索缓存,您会发现确实有相当多的缓存正在进行。 【参考方案1】:是的。 Json.NET 在其IContractResolver
类DefaultContractResolver
和CamelCasePropertyNamesContractResolver
中缓存类型序列化信息。除非您指定自定义合同解析器,否则此信息将被缓存并重复使用。
对于DefaultContractResolver
,在内部维护一个全局静态实例,只要应用程序未指定其自己的合约解析器,Json.NET 就会使用该实例。另一方面,CamelCasePropertyNamesContractResolver
维护在所有实例之间共享的静态表。 (我认为不一致是由遗留问题引起的;有关详细信息,请参阅here。)
这两种类型都被设计为完全线程安全的,因此线程之间的共享应该不是问题。
如果您选择实现和实例化您自己的合约解析器,那么只有在您缓存和重用合约解析器实例本身时,类型信息才会被缓存和重用。因此,Newtonsoft recommends:
为了提高性能,您应该创建一次合同解析器并尽可能重用实例。解析合约很慢,IContractResolver 的实现通常会缓存合约。
如果内存消耗是一个问题,无论出于何种原因,您需要最小化缓存合约永久占用的内存,您可以构建自己的 DefaultContractResolver
本地实例(或一些自定义子类),使用它进行序列化,然后立即删除对它的所有引用,例如:
public class JsonExtensions
public static string SerializeObjectNoCache<T>(T obj, JsonSerializerSettings settings = null)
settings = settings ?? new JsonSerializerSettings();
bool reset = (settings.ContractResolver == null);
if (reset)
// To reduce memory footprint, do not cache contract information in the global contract resolver.
settings.ContractResolver = new DefaultContractResolver();
try
return JsonConvert.SerializeObject(obj, settings);
finally
if (reset)
settings.ContractResolver = null;
如果您使用的是CamelCasePropertyNamesContractResolver
,请使用适当的naming strategy 切换到DefaultContractResolver
,例如:
settings.ContractResolver = new DefaultContractResolver NamingStrategy = new CamelCaseNamingStrategy() ;
大部分缓存的合约内存 (but not all) 最终会被垃圾回收。当然,这样做,序列化性能可能会受到很大影响。 (一些包含诸如enum
类型和数据协定属性的反映信息的表是全局共享的,不会被回收。)
有关详细信息,请参阅 Newtonsoft 的 Performance Tips: Reuse Contract Resolver。
【讨论】:
我们在 UT 中看到保存在MyContractResolver : CamelCasePropertyNamesContractResolver
类型中的合约是静态缓存的,即使跨多个 MyContractResolver
类型也是如此。当一些 UT 一起运行时,这会导致令人惊讶的失败,因为它们没有根据需要设置合约。重用同一 ContractResolver
实例的指针是否仍然有效?
@ElFik - CamelCasePropertyNamesContractResolver
的行为与 DefaultContractResolver
不同——无论您是否愿意,它都会全局缓存合约信息。如果您不想这样,请使用适当的命名策略切换到 DefaultContractResolver
。
@dbc 和 ElFik 你拯救了我的一天!这是 CamelCasePropertyNamesContractResolver 实现的可怕失败。非常感谢!以上是关于Json.NET 是不是缓存类型的序列化信息?的主要内容,如果未能解决你的问题,请参考以下文章
一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型;
序列化特定类型时如何使 JSON.Net 序列化程序调用 ToString()?