Json.NET 是否缓存类型的序列化信息? [英] Does Json.NET cache types' serialization information?

查看:21
本文介绍了Json.NET 是否缓存类型的序列化信息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 .NET 世界中,当涉及到对象序列化时,通常会在运行时检查对象的字段和属性.为这项工作使用反射通常很慢,并且在处理大量对象时是不可取的.另一种方法是使用 IL 发射或构建表达式树,以提供比反射更显着的性能提升.后者是大多数现代库在处理序列化时选择的.然而,在运行时构建和发布 IL 需要时间,并且只有当这些信息被缓存并重用于相同类型的对象时,投资才会得到回报.

In .NET world, when it comes to object serialization, it usually goes into inspecting the object's fields and properties at runtime. Using reflection for this job is usually slow and is undesirable when dealing with large sets of objects. The other way is using IL emit or building expression trees that provide significant performance gain over reflection. And the latter is most modern libraries pick when dealing with serialization. However building and emitting IL at runtime takes time, and the investment is only paid back if this information is cached and reused for objects of the same type.

在使用Json.NET时,我不清楚使用了上面描述的哪种方法,如果确实使用了后者,是否使用了缓存.

When using Json.NET, it is not clear to me which method described above is used, and if the latter is indeed used, whether the caching is used.

例如,当我这样做时:

JsonConvert.SerializeObject(new Foo { value = 1 });

Json.NET 是否会构建 Foo 的成员访问信息并缓存以供以后重用?

Does Json.NET build the Foo's member access info and cache to reuse it later?

推荐答案

是的,确实如此. Json.NET 在其 IContractResolverDefaultContractResolverCamelCasePropertyNamesContractResolver.除非您指定自定义合同解析器,否则此信息将被缓存和重用.

Yes, it does. Json.NET caches type serialization information inside its IContractResolver classes DefaultContractResolver and CamelCasePropertyNamesContractResolver. Unless you specify a custom contract resolver, this information is cached and reused.

对于 DefaultContractResolver,在内部维护一个全局静态实例,每当应用程序未指定自己的合约解析器时,Json.NET 就会使用该实例.CamelCasePropertyNamesContractResolver 另一方面,维护在所有实例之间共享的静态表.(我认为不一致是由遗留问题引起的;请参阅此处 了解详情.)

For DefaultContractResolver a global static instance is maintained internally that Json.NET uses whenever the application does not specify its own contract resolver. CamelCasePropertyNamesContractResolver, on the other hand, maintains static tables that are shared across all instances. (I believe the inconsistency arises from legacy issues; see here for details.)

这两种类型都被设计为完全线程安全的,因此线程之间的共享应该不成问题.

Both of these types are designed to be fully thread-safe so sharing between threads should not be a problem.

如果您选择实现和实例化自己的合约解析器,那么只有缓存和重用合约解析器实例本身时,才会缓存和重用类型信息.因此,Newtonsoft 建议:

If you choose to implement and instantiate your own contract resolver, then type information will only be cached and reused if you cache and reuse the contract resolver instance itself. Thus, Newtonsoft recommends:

为了提高性能,您应该创建一次合约解析器,并在可能的情况下重用实例.解析合约很慢,并且 IContractResolver 的实现通常会缓存合约.

For performance you should create a contract resolver once and reuse instances when possible. Resolving contracts is slow and implementations of IContractResolver typically cache contracts.

如果内存消耗是一个问题,并且无论出于何种原因您需要最小化缓存合约永久占用的内存,您可以构建自己的 DefaultContractResolver 本地实例(或一些自定义子类),使用它进行序列化,然后立即删除对它的所有引用,例如:

If memory consumption is a problem and for whatever reason you need to minimize the memory permanently taken by cached contracts, you can construct your own local instance of DefaultContractResolver (or some custom subclass), serialize using that, and then immediately remove all references to it, e.g.:

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,请使用适当的 命名策略 如:

And if you are using CamelCasePropertyNamesContractResolver, switch to DefaultContractResolver with an appropriate naming strategy such as:

settings.ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() };

大部分缓存的合约内存(但不是全部) 最终会被垃圾收集.当然,如果这样做,序列化性能可能会受到很大影响.(一些包含有关例如 enum 类型和数据协定属性的反射信息的表是全局共享的,不会被回收.)

The majority of cached contract memory (but not all) will eventually get garbage collected. Of course, by doing this, serialization performance may suffer substantially. (Some tables containing reflected information about e.g. enum types and data contract attributes are shared globally and not reclaimed.)

有关更多信息,请参阅 Newtonsoft 的性能提示:重用合同解析器.

For further information see Newtonsoft's Performance Tips: Reuse Contract Resolver.

这篇关于Json.NET 是否缓存类型的序列化信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆