Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Json.NET cache types' serialization information?

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.

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.

For example, when I do:

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

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

like image 795
KFL Avatar asked Nov 06 '15 01:11

KFL


People also ask

What is cache serialization?

Cache data when transmitted over the network needs to be serialized. The serialization process traverses the existing objects, extracts the data and converts it into the serialized data. Data is then transmitted over the network and then the process of deserialization reads the serialized.

What is serialization in C# JSON?

Serialization is the process of converting . NET objects such as strings into a JSON format and deserialization is the process of converting JSON data into . NET objects.

How to speed up Json serialization?

Speed up serialization To speed up your program, you need to insert a buffer between serializeJson() and WiFiClient . You can do that using the StreamUtils library.

Does Newtonsoft JSON use reflection?

Newtonsoft. Json uses reflection to get constructor parameters and then tries to find closest match by name of these constructor parameters to object's properties. It also checks type of property and parameters to match.


1 Answers

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.

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.

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:

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.

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;         }     } } 

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

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

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.)

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

like image 184
dbc Avatar answered Sep 30 '22 19:09

dbc