Follow up: Workaround for XmlSerializer assembly leaks

 
A while ago, Paul Wilson and Kirk Allen Evans reported that the XmlSerializer is leaking assemblies when the serializer object was instantiated with any of the constructors but the most basic one. The simple XmlSerializer constructor has logic to re-use the temporary assemblies if it already built them for a given type. The more complex constructors are missing that caching logic and allow the temporary assemblies to leak if you don't keep the serializer instance around in your program.
 
the other day, I found out that the XmlSerializer assembly leak is not going to be fixed in Whidbey. Within a few days of me reading that, John Bristowe was asking why there isn’t anything in the Mvp.Xml project to work around that issue. And because I didn't have a real good answer to that I sat down and wrote one, because there should be.
 
The result is the XmlSerializerCache class. It's very easy to use. You simply obtain XmlSerializer instances from the various overloads of XmlSerializerCache.GetSerializer() instead of the instantiating a serializer instance with the XmlSerializer constructor. The signatures of the GetSerializer() method match those of the XmlSerializer constructor.
 
XmlSerializer ser = XmlSerializerCache.GetSerializer( typeof( MyClass ), "http://www.mvpxml.org/mytool" );
 
The XmlSerializerCache canonicalizes the contents of the parameter list to reduce the amount of serializer objects in the application. For example, canonicalization recognizes that an XmlSerializer instance created for this request:
 
XmlSerializerCache cache = new XmlSerializerCache();
XmlSerializer ser1 = cache.GetSerializer( typeof(MyType), new Type[] { typeof(TypeOne), typeof(TypeTwo) } );
 
is compatible with this request:
 
XmlSerializerCache cache = new XmlSerializerCache();
XmlSerializer ser2 = cache.GetSerializer( typeof(MyType), new Type[] { typeof(TypeTwo), typeof(TypeOne) } );
 
The GetSerializer method checks cache for compatible instances that are compatible with the method parameters before constructing a new instance to minimize the number of created serializers. The compatibility check computes a fingerprint from the method parameters. This computation looks at every property of the passed in parameters. Yet this operation is still less expensive than reflecting over an object graph to create code and compile temporary assemblies and it prevents "leaking" memory due to orphaned assemblies that you cannot unload.
 
Parameter canonicalization is not the only feature of the XmlSerializerCache. It also allows you to monitor what it's doing, through raising events and via two performance counters. Both counters are in the category Mvp.Xml.XmlSerializerCache. Make sure you install the Mvp.Xml with the .msi to create and delete the performance counters.
 
The performance first counter  "Cache Hits" exposes the number of currently cached XmlSerializer instances. The second counter "Cached Instances" reflects the number of cache hits, i.e. how many times the instances were successfully retrieved from the cache instead of creating a new one.
 
In addition to the performance counters, the XmlSerializerCache also features a pair of events to track its operations from within the program that is using it. The parameters of these events contain the parameter of the request to the XmlSerializerCache's in case you want to track or log what serializers are created for example.

4 Comments

  • Surely those who might consider using this utility will not be looking to:

    1. Reference an entire assembly
    2. Install your custom performance counters on client machines

    ... given that this behavior is easily reproducible.

    Something that should be nothing but code posted on a blog is bring distributed via an msi installer?

    Surely you haven't given your target audience any thought. If you need an msi installer to utilize this class, then you have no business attempting to fine tune your apps performance. It's as simple as that.

    Good effort, but this smells like over engineering.

  • @Randy,

    The XMLMVP Lib acutally has a number of other helpful XML related helpers you might like. If you don't, you can still pull the code for the class and the test cases off sourceforge: http://sourceforge.net/projects/mvp-xml/

    HTH,
    Christoph

  • This solution works for me! Only it hasn't resolved my memory leaks completely...

  • Awesome, was tearing my hair out trying to find out why my XML intensive .NET app about was eating 1GB of memory before random crashes. Switched to the XMLSerializaerCahce and now it doesn't even break a sweat. Thanks!

Comments have been disabled for this content.