Search code examples
c#asp.net-mvciisgarbage-collectioncontroller-factory

Controllers created by System.Web.Mvc.IControllerFactory.CreateController are not disposed


I have created a class - SystemConfig - derived from IControllerFactory which I want to use to create Controllers.

In Global.asax.cs Application_Start(), I instantiate SystemConfig and register it:

var system = new SystemConfig();
ControllerBuilder.Current.SetControllerFactory(system);

In SystemConfig, I implemented CreateController

public IController CreateController(RequestContext requestContext,
    String controllerName)
{
    switch (controllerName.ToLower())
    {
        case "log": return new Controllers.LogController();
        case "account": return new Controllers.AccountController( args as needed );

This seems to work well. The endpoints exposed by AccountController (for example) process requests as expected.

But the controller that is new'ed in CreateController is never disposed. The memory used by the IIS process just grows and grows.

I produced a dump and examined it with WinDbg

  !dumpheap -type MyApp.Controllers.AccountController -stat

revealed that there were 4372 instances of AccountController. The longer the application ran, the more controllers were left in memory

After 29 hours the App Pool is recycled and memory pressure is relieved, but this is not a good solution.

Why is the AccountController instance not disposed once the web request has been processed and a response returned to the client?


Solution

  • With the code shown in the OP, the controller instances ought to go out of scope and get garbage-collected (which is not the same as getting disposed) once they've handled requests.

    My guess is that

    • either the real code looks different than what is shown here, so that some other code holds on to Controllers instances,
    • or the Controller 'registers' itself with a dependency or global variable when it runs, e.g. by calling some method and passing this as an argument,
    • or the Controllers start some long-running task (logging?) that never properly terminates.

    If you want to dispose of the Controllers, you can let SystemConfig implement the ReleaseController method, but that's only relevant if Controllers actually implement IDisposable, or hold on to resources that do.