Thursday, November 20, 2008

.NET XmlSerializer Memory Leak

Production maintenance team reports the memory usage of IIS worker process keeping growing in one high-traffic site, which indicating the memory leak. After investigation, one of culprits is from XmlSerializer:
Type[] relatedTypes = new Type[1];
type[0] = typeof(AppObject);
XmlSerializer serializer = new XmlSerializer(typeof(AppConfig), relatedTypes);
Every time this serializer is created, a dynamic assembly is also generated at run time and is loaded into memory to do the XML serialization. The problem is that once a .NET assembly (dynamic or static) is loaded, there's no way you can clean it through code, and it will only be removed from the memory until the whole application is unloaded. The result is a memory leak with more and more dynamic XML serialization assemblies added into memory.

The solution is use XmlSerialzer constructor with only Type parameter:
XmlSerializer serializer = new XmlSerializer(typeof(object));
Alternative is to cache the XmlSerialzer object for the first time when you can't use such constructor, and reuse it later. In fact .NET caches XmlSerialzer that created only by Type constructor.

This seems to be an known issue. We google it and found many people having same problem. A good article showing the details of tracing this issue can be found here.

Sunday, November 09, 2008

ASP.NET Cache Callback

ASP.NET Cache Callback

ASP.NET Cache supports CacheItemRemovedCallback option since .NET 1.1 (http://msdn.microsoft.com/en-us/library/aa478965.aspx), and we can do some interesting things such as logging inside the callback function. But a big limitation on it is that we can’t do cache validation to keep or refresh cache data in this callback function:

"One potential use for this feature would be to refresh cached data in the background so that users never need to wait for the data to be populated, but the data is kept relatively fresh. Unfortunately in practice, this doesn't work very well with the current version of the caching API, because the callback doesn't fire or complete execution prior to the cached item being removed from the cache. Thus, a user will frequently make a request that will try to access the cached value, find that it is null, and be forced to wait for it to repopulate."

From .NET 3.5, we have a new CacheItemUpdateCallback delegate for caching handling (http://msdn.microsoft.com/en-us/library/system.web.caching.cacheitemupdatecallback.aspx). Now we can periodically update the cache by the callback function. The new overloading Cache Insert method is:
HttpRuntime.Cache.Insert(
stringKey,
objectValue,
cacheDependencies,
dateTimeAbsoluteExpiration,
timeSpanSlidingExpiration,
cacheUpdateCallback)
The callback function signature is:

public delegate void CacheItemUpdateCallback(
string key,
CacheItemUpdateReason reason,
out Object expensiveObject,
out CacheDependency dependency,
out DateTime absoluteExpiration,
out TimeSpan slidingExpiration
)
This new feature is very handy when we need to automatically refresh the cache in background.