6

I have an AsyncController set up to perform long-polling actions. This all works fine, however a colleague has noticed a memory leak on the server that appears to increase with every new connection.

I've created a little application to request from this page thousands of times and I'm monitoring the memory usage for the IIS process. Each connection increases the memory usage, but doesn't fall all the way back down when the client has disconnected.

After further investigation, I found that this still happens even when I replace my AsyncController with a standard Controller that does nothing but this:

public class WaitController : Controller
{
    public JsonResult Member(string oauth_token, int service_id, bool busy = false)
    {
        return Json(new
        {
            ready = false,
        }, JsonRequestBehavior.AllowGet);
    }
}

Although in this, there is not as much memory usage, the behaviour appears to be exactly the same.

I've ran a memory profiler to show the difference between 10,000 connections and there is barely anything there. The most memory is taken up by instances of ExpiresEntry[] from System.Web.Caching or System.Runtime.Caching, however these total to nothing in comparison to the memory increase I'm getting on the IIS worker process.

My question is, is IIS doing this by design? Perhaps this had been allocated for connection threads, which are hanging around just in-case they're needed later? Is this a bug with IIS, ASP.NET or MVC 4?

It was my decision to use MVC 4's WebAPI features for this because we want this to be flexible, maintainable, future-proof and to be accessed via AJAX. It also seemed to make sense from a development point of view, as we have built the website in MVC 4 too.

However, a colleague has now raised this as a critical problem with the system architecture as we will (in the future) need thousands of clients connected. He is suggesting we use WCF instead. So, bonus question - will using WCF resolve these problems?

Connell
  • 13,925
  • 11
  • 59
  • 92
  • Are you sure the memory is leaking? Is it possible it's just holding onto it because there's not enough pressure for it to give it up? Have you verified that if you continue running your connection test that the server will, eventually, run out of memory? – Pete Feb 27 '13 at 14:56
  • @Pete it does start slowing down. I've never seen it actually run out of memory but the whole application pool gradually slows down to a point where it is unusable. This is resolved by restarting the application pool. Does IIS need 'pressure' to give up allocated memory then? The bad performance I suppose could just be each connection waiting in a queue for it to be processed. – Connell Feb 27 '13 at 15:03

2 Answers2

1

There's a great article from a MS Field Engineer about this subject. Might be of help.

rusev
  • 1,880
  • 2
  • 17
  • 14
  • Is this saying that it is expected behaviour? `"Memory fragmentation and other natural degradation cannot be avoided and recycling ensures that the applications are periodically cleaned up"`. Do Microsoft encourage us to solve this problem by automatically recycling the application pool? – Connell Feb 27 '13 at 15:51
  • That is what I usually do. :) – rusev Feb 27 '13 at 16:05
0

After more experimenting and testing, I've discovered this, unfortunately, cannot be prevented. It seems to be either by design or a real deep-rooted issue with IIS.

I changed my method to use a lower-level option: Implement an IHttpAsyncHandler to do the same thing. I used a custom HttpHandler route for MVC to allow me to use the exact same URLs as I was using before. The problem still existed, but on a slightly smaller scale.

I then tried a completely blank IHttpHandler that simply returns { ready: false } (as my code would do on a timeout). No other code included in the HttpHandler, but the same issue still occurs.

Next, I tried a completely blank WCF service that also returned { ready: false }. Same issue, but on an even smaller scale this time.

As the link @rusev's answer suggests:

Memory fragmentation and other natural degradation cannot be avoided and recycling ensures that the applications are periodically cleaned up.

This may be the cause of the problem. I can imagine that because there are more overheads when using an MVC Controller, the fragmentation just happens faster. Using lower-level methods such as an HttpHandler or a WCF service would use less memory per connection, therefore cause less fragmentation.

Community
  • 1
  • 1
Connell
  • 13,925
  • 11
  • 59
  • 92