Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /var/www/rassie.dk/blog.rassie.dk/wp-content/themes/suffusion/functions/media.php on line 666

Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /var/www/rassie.dk/blog.rassie.dk/wp-content/themes/suffusion/functions/media.php on line 671

Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /var/www/rassie.dk/blog.rassie.dk/wp-content/themes/suffusion/functions/media.php on line 684

Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /var/www/rassie.dk/blog.rassie.dk/wp-content/themes/suffusion/functions/media.php on line 689

Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /var/www/rassie.dk/blog.rassie.dk/wp-content/themes/suffusion/functions/media.php on line 694
Leaking dynamic assemblies | Rasmus' Ramblings on IT and other stuff
Apr 022014
 

We have a .net library that communicates with a web service over a “REST-like” interface. To send data to the interface, we need to PUT or POST XML data.

The library is a few years old and uses the WCF REST implementation that existed before it became a part of the .net framework. It was called the WCF REST Starter Kit, and has since been superceeded by built-in classes, but it works, and we haven’t had the inclination or time to change code that works.

The communications library was originally used by a server-side Windows Service which was only used by a few users at a time, and its PUT or POST operations are rarely used.

Recently, we started to use the communication library in a new project where it is used in a multi-tenant server with many simultaneous users, and its PUT and POST operations are called much more often. This new usage made a memory leak much more significant than before.

It took me a few days to figure out what the problem was – the server application is big, and I didn’t really have any idea of what was causing the leak. Initially I looked at whether it kept Entity Framework data in memory longer than necessary, but that was a wild goose chase. In the process I read a lot of articles about .net memory leaks, and had stumbled upon an old blog post by Tess Ferrandez from Microsoft.

It turned that the blog post was the clue to finding the problem: The application was leaking dynamic assemblies. These aren’t garbage collected by the .net garbage collector – it doesn’t know whether the code needs to use them later.

The code that triggered the problem was something like this:

public void NewMessage(Message message)
{
    var httpclient = new HttpClient("https://server/service");
    var content = HttpContentExtensions.CreateXmlSerializable<Message>(message, _encoding, "application/xml; charset=UTF-8", null);
    httpclient.Post("/message/new", content);
}

The line that generates the dynamic assembly is the call to HttpContentExtensions.CreateXmlSerializable. It internally creates an XmlSerializer for the Message type and returns a HttpContent object that holds the generated XML string. Even though the XmlSerializer is garbage collected, its dynamic assemblies stay on.

This meant that our application leaked a dynamic assembly on each call to the NewMessage and other similar methods.

The fix wasn’t hard: Cache an XmlSerializer instance for each possible type to send.

private readonly Dictionary<Type, XmlSerializer> _serializers = new Dictionary<Type, XmlSerializer>(); 

private HttpContent createHttpContent<T>(T contentObject)
{
    XmlSerializer serializer;
    if (!_serializers.TryGetValue(contentObject.GetType(), out serializer)) 
    {
        serializer = new XmlSerializer(contentObject.GetType());
        _serializers.Add(contentObject.GetType(), serializer);
    }
    return HttpContentExtensions.CreateXmlSerializable<T>(contentObject, serializer, _encoding, "application/xml; charset=UTF-8");
}

public void NewMessage(Message message)
{
    var httpclient = new HttpClient("https://server/service");
    var content = createHttpContent<Message>(message);
    httpclient.Post("/message/new", content);
}

The _serializers Dictionary contains an instance of XmlSerializer for each type that ever needed to be serialized by the createHttpContent method, and the other overload of HttpContentExtensions.CreateXmlSerializable takes that serializer as a parameter, instead of creating a new XmlSerializer for each call.

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)