Friday, April 25, 2014

Microsoft.Web.Administration Memory Leak

*DISCLAIMER: THIS IS REPORTED FIXED IN IIS 8.0*

I work with the ServerManager class from the Microsoft.Web.Administration assembly quite a bit on a project for work. We use it to track websites performance, etc… After looking in dotPeek I found out that this assembly is just a COM wrapper for IIS management. As I started deploying this software to servers with more websites, I noticed that the memory growth for my monitoring process was going through the roof (usually runs with 90-150mb memory, I had instances over 9gb of memory).

After going through the paces of doing memory dumps, using windbg to check the memory, there was a very large native heap, while the managed heap was in the expected range. After some google-fu, I found this bug reported on the Visual Studio feedback site.

The following code which uses Microsoft.Web.Administration.dll, version 7, causes a memory leak. No way to work around this issue without running it in a separate process.
namespace testmemoryleak
{
    using System;
    using System.Threading;
    using Microsoft.Web.Administration;
    static class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                using (var mgr = new ServerManager())
                {
                    Console.WriteLine(mgr.WorkerProcesses.Count);
                }
                Thread.Sleep(1);
            }
        }
    }
}

That was my exact problem, and this code duplicated it 100%. I then opened up a support ticket with Microsoft, and quickly they gave me a work around for the leak (posted to the thread mentioned above as well).

Instead of:

namespace testmemoryleak
{
using System;
using System.Threading;
using Microsoft.Web.Administration;
static class Program
{
static void Main(string[] args)
{
while (true)
{
using (var mgr = new ServerManager())
{
Console.WriteLine(mgr.WorkerProcesses.Count);
}
Thread.Sleep(1);
}
}
}
}

I use the static method on the ServerManager OpenRemote("localhost")

namespace testmemoryleak
{
using System;
using System.Threading;
using Microsoft.Web.Administration;
static class Program
{
static void Main(string[] args)
{
while (true)
{
using (var mgr = ServerManager.OpenRemote("localhost"))
{
Console.WriteLine(mgr.WorkerProcesses.Count);
}
Thread.Sleep(1);
}
}
}
}

Once deployed, the memory leak was gone! Oddly enough, the IIS Management Snap-In (inetsrv) also uses the remote connectivity as well, so it would have never suffered from it.


I hope this post helps other people out there who suffer from the same leak.

3 comments:

Phil Dobson said...

Thank you Tom you saved my bacon

I had a similar issue with a memory leak. In my case I was making a series of calls in order to delete a site (and its application pool and its config location node). I load tested this and after deleting 30 sites I would get System.Runtime.InteropServices.COMException (0x80070008): Not enough storage is available to process this command. (Exception from HRESULT: 0x80070008) when calling CommitChanges() observing that my service had used up about 1.8 GB of RAM. Your work-around solved my issue completely. I am using IIS 8.5 on Windows Server 2012 R2 and version 8.5.9600.17042 of the Microsoft.Web.Administration.dll

Ember said...

I found that memory leak in such codes:
public bool ExistAppPool(string appPoolName)
{
return _serverManager.ApplicationPools[appPoolName]
}

and
Site oneSite = _serverManager.Sites[siteName];

Such [ ] operation on Collection cause 3-6MB memory leak.
But the way you find out to across the problem is also applicable for this.
Thanks for your resolution!!The memory leak is gone!

monicka said...

Qbigpro is the best web designing company in chennai.we are doing web designing and developing website creation website maintenance graphic designing google.
web design company in velachery.