Friday, December 23, 2005

.NET is not a silver bullet

Having worked with .NET applications for a few years I have seen the unravelling of a number of strategies where managed code was expected to solve some of the issues that had gone before in the bad old days of native code.

Surprise! We have the very same issues merely packaged differently. I guess that every inter-process communication functionality ever written in native code was totally different, which no doubt contributed to the issues that invariably surrounded their implementation. With the one size fits all approach of .NET remoting we simply have more subtle and difficult to detect problems.

I was recently tasked with tracking down some mysterious memory leaks in a real-time application that uses remoting to handle data from the server. After analysing the code in the client, I discovered that although our application's virtual memory was increasing, the leaking classes were not visible in the profiler. Part of this occurred when we received data in the client from the server as a DataTable.

We requested code from our suppliers and I rebuilt our application for further analysis of the third party code. Still no luck. This leak still occurred and at the same point, implicating the remoting framework. My colleagues looked on in disbelief as I explained the CLR remoting library was leaking memory. Having developed a strategy to mitigate this I later found this knowledge base entry on the Microsoft website;

Q322975. BUG: Passing large quantities of data in .NET Remoting calls causes an unexpected exception to occur.

What this basically means is that if you send a substantial amount of data such as a DataTable via remoting the sockets layer leaks. Not an ideal situation and one that is hardly publicised by Microsoft.

To make a bad situation worse, part of the solution to this massive memory leak had to be an attempt to trigger garbage collections. The CLR is notorious for deferring garbage collection, especially on large objects.

This approach of triggering garbage collections is fraught with frustration. GC.Collect(), in order to be effective requires a subsequent call to GC.WaitForPendingFinalizers().

Don't go there. There is no guarantee that this method will return and I have seen it hang. It is a synchronous call that will be blocked should there be a deadlock in a finalizer, whether in your code, a library you use or within the CLR.

So the conclusion? If you're writing an application that will need to pass tens of megabytes of data. Don't use .NET remoting.

No comments: