Windsor Castle Interceptor Memory Leak

I am facing an issue where my program runs out of memory when using Castle Windsor and interceptors. It is reproduced using the following code:

public interface ITest{}
public class Test : ITest {}
class TestInterceptor:IInterceptor {
    public void Intercept(IInvocation invocation) {}
}
class Program {
    static void Main(string[] args) {
        while(true) {
            using(var container = new WindsorContainer()) {
                container.Register(Component.For<TestInterceptor>());
                container.Register(Component.
                    For<ITest>().
                    ImplementedBy<Test>().
                    Interceptors(
                        InterceptorReference.ForType<TestInterceptor>()
                    ).Anywhere);

                var tst = container.Resolve<ITest>();
            }
        }
    }
}

      

This is how memory usage develops:

memory usage

So what threw me off was that I thought there was a memory leak without code management, but after a lot of debugging, I found out that the problem is with the generation of the prxoy interceptor: a new (dynamic) build with a proxy type is injected into the environment execution every time it is allowed:

interceptor proxies inserted

Now I think you can solve this with

  • using a global (static) container for the whole application, but at the moment this is not possible for my application (I read that this is the preferred way to do this, not really clear why)
  • creating a proxy myself using static ProxyGenerator

    and using the UsingFactoryMethod

    instantiation method (which I am doing now)

This leaves me 3 questions:

  • Am I using Castle Windsor correctly (the docs are not entirely clear), and if so, is it possible to cache the proxy type for Castle Windsor?
  • Should Castle Windsor automatically cache the proxy type (or: is the current behavior a bug)?
  • How do you debug (using perfmon for example) that dynamically generated assemblies eat up all your memory?

Thank.

+3


source to share


3 answers


I read that this is the preferred way of doing this, not really clear why

One container for the lifetime of the application is preferred because:



  • Containers are highly optimized for this scenario. Often the generation of delegates using Reflection.Emit and information is cached. This provides a one-time performance improvement (for a container instance) and speeds up all subsequent requests. Creating a new instance for each request can slow down the performance of your application, as all this reflection and code emission is repeated over and over.
  • But beyond this optimization, the registration process itself takes time. It may be a one-time cost, but you do it over and over.
  • Configuring a container can get a lot more complicated. Registering the instances that must survive the request is much more difficult. There are ways to work around this, but this often results in a container configuration that is difficult to understand, difficult to maintain, and has bugs. Castle Windsor contains a container diagnostic feature that allows you to check a container, but it cannot scan through a container.
+3


source


Read the documentation carefully . Make interceptors always transitory.

Correct code:



public interface ITest{}
public class Test : ITest {}
class TestInterceptor:IInterceptor {
     public void Intercept(IInvocation invocation) {}
}
class Program {
static void Main(string[] args) {
    while(true) {
        using(var container = new WindsorContainer()) {
            container.Register(Component.For<TestInterceptor>().LifestyleTransient());
            container.Register(Component.
                For<ITest>().
                ImplementedBy<Test>().
                Interceptors(
                    InterceptorReference.ForType<TestInterceptor>()
                ).Anywhere);

            var tst = container.Resolve<ITest>();
        }
    }
}
}

      

+1


source


I ran into this problem today. To answer # 3 from the original post, the performance counter [.NET Clr Loading -> Current Assemblies] would show a linearly increasing number of assemblies when your code snippet runs, due to the loading of dynamic proxies.

+1


source







All Articles