Castle Windsor Interceptor内存泄漏

时间:2013-02-06 14:08:14

标签: .net memory-leaks castle-windsor

我遇到了一个问题,当使用Castle Windsor和拦截器时,我的程序会耗尽内存。它可以使用以下代码重现:

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>();
            }
        }
    }
}

这就是内存使用的发展方式:

memory usage

所以让我失望的是,我认为有一个非托管代码内存泄漏,但经过大量调试后我发现问题出在拦截器prxoy生成:一个新的(动态)程序集与代理类型在每次解析时都会引入运行时:

interceptor proxies inserted

现在,我想你可以通过

来解决这个问题
  1. 为整个应用程序使用全局(静态)容器,但目前这对我的应用程序来说是不可行的(我读过这是执行此操作的首选方式,并不完全清楚原因)
  2. 使用静态ProxyGenerator自己生成代理并使用UsingFactoryMethod生成实例的方式(我现在这样做)
  3. 这让我有三个问题:

    1. 我是否正确使用Castle Windsor(文档并不完全清楚),如果有的话,Castle Windsor会有一种缓存代理类型的方法吗?
    2. Castle Windsor应该自动缓存代理类型(或者:当前行为是一个错误)?
    3. 你如何调试(例如使用perfmon)动态生成的程序集正在占用你所有的内存?
    4. 谢谢。

3 个答案:

答案 0 :(得分:3)

  

我读过这是这样做的首选方式,并不完全清楚为什么

首选单个容器,因为:

  • 容器针对此方案进行了高度优化。通常使用Reflection.Emit和信息生成代理。这样可以获得一次性性能(每个容器实例)并加快所有后续请求。为每个请求创建一个新实例可能会耗尽应用程序的性能,因为所有这些反射和代码发出都在一次又一次地肆虐。
  • 但除了这种优化之外,注册过程本身也需要时间。这可能是一次性费用,但你一遍又一遍地做。
  • 配置容器会变得更加困难。注册应该比请求更长的实例要困难得多。有很多方法,但这通常会导致容器配置难以掌握,难以维护并且存在错误。 Castle Windsor包含一个允许验证容器的container diagnostics feature,但它无法进行跨容器验证。

答案 1 :(得分:1)

我今天刚遇到同样的问题。要回答原帖中的#3,性能计数器[.NET Clr Loading - &gt;由于加载了动态代理类型,运行代码片段时,当前程序集]会显示线性增加的程序集数。

答案 2 :(得分:0)

仔细阅读the documentation使拦截器始终处于暂态状态。

正确的代码是:

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>();
        }
    }
}
}