.net Castle Windsor拦截器内存泄漏

.net Castle Windsor拦截器内存泄漏,.net,memory-leaks,castle-windsor,.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)

在使用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>();
            }
        }
    }
}
公共接口ITest{}
公共类测试:ITest{}
类测试接收器:I接收器{
公共无效拦截(IInvocation调用){}
}
班级计划{
静态void Main(字符串[]参数){
while(true){
使用(var container=new WindsorContainer()){
container.Register(Component.For());
容器。寄存器(组件)。
For()。
由()实现。
拦截器(
InterceptorReference.ForType()
)(任何地方);
var tst=container.Resolve();
}
}
}
}
这就是内存使用的发展过程:

因此,让我感到不快的是,我认为存在非托管代码内存泄漏,但经过大量调试后,我发现问题出在拦截器prxoy生成上:每次解决问题时,都会向运行时引入一个新的(动态)具有代理类型的程序集:

现在,我想你可以通过

  • 为整个应用程序使用全局(静态)容器,但目前这对我的应用程序不可行(我了解到这是首选方法,但不完全清楚原因)
  • 使用静态
    ProxyGenerator
    自己生成代理,并使用
    UsingFactoryMethod
    生成实例的方式(我现在这样做)
  • 这给我留下了三个问题:

  • 我是否正确使用Castle Windsor(文档不完全清楚),如果是,Castle Windsor是否有办法缓存代理类型
  • Castle Windsor是否应自动缓存代理类型(或:当前行为是否为bug)
  • 如何调试(例如使用perfmon)动态生成的程序集占用了您所有的内存
  • 多谢各位

    我读到这是做这件事的首选方式,不完全清楚为什么

    最好在应用程序的生命周期内使用一个容器,因为:

    • 容器针对这种情况进行了高度优化。通常使用Reflection.Emit生成委托,并缓存信息。这会一次性影响性能(每个容器实例),并加速所有后续请求。每个请求创建一个新实例可能会耗尽应用程序的性能,因为所有这些反射和代码发出都会一次又一次地发生
    • 但除了这种优化,注册过程本身也需要时间。这可能是一次性的成本,但你要一次又一次地这么做
    • 配置容器可能变得更加困难。注册应该比请求寿命长的实例要困难得多。有很多方法可以解决这个问题,但这通常会导致容器配置难以掌握、难以维护并且存在bug。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>().LifestyleTransient());
                    container.Register(Component.
                        For<ITest>().
                        ImplementedBy<Test>().
                        Interceptors(
                            InterceptorReference.ForType<TestInterceptor>()
                        ).Anywhere);
        
                    var tst = container.Resolve<ITest>();
                }
            }
        }
        }
        
        公共接口ITest{}
        公共类测试:ITest{}
        类测试接收器:I接收器{
        公共无效拦截(IInvocation调用){}
        }
        班级计划{
        静态void Main(字符串[]参数){
        while(true){
        使用(var container=new WindsorContainer()){
        container.Register(Component.For().LifestyleTransient());
        容器。寄存器(组件)。
        For()。
        由()实现。
        拦截器(
        InterceptorReference.ForType()
        )(任何地方);
        var tst=container.Resolve();
        }
        }
        }
        }
        
        我今天遇到了同样的问题。为了回答原始帖子中的第3个问题,性能计数器[.NET Clr Loading->Current Assembly]在运行代码片段时,由于加载的是动态代理类型,程序集的数量会线性增加。

        我想你是对的。在这样做时,很容易引入内存泄漏和线程安全问题。前2点可以通过显式允许缓存该工作来减轻。@Freek,该工作已缓存。它缓存在容器实例中。在AppDomain级别缓存它本身会导致内存泄漏。是的,这是我理解的部分。但我的意思是缓存可以显式地工作,以便在实例化新容器实例时可以利用缓存步骤。IIRC这很像NHibernates SessionFactory/会话分离。当只有一个容器实例时,不应该“很容易引入内存泄漏”,因为默认情况下,所有注册都应该是暂时的。在这种情况下,每个请求一个容器和每个应用程序域一个容器之间的生命周期(和风险)没有区别,也没有线程安全问题。但在温莎,默认情况下是单例,容器跟踪(可能)瞬态。所以,如果你自己解决了一个暂时的问题(这可能是一个坏主意),并且在使用后不释放它,那么你将面临内存问题。尽管这可能会耗尽应用程序的性能,但为每个请求创建一个容器实例不会导致内存泄漏。您尝试过这个吗?它有完全相同的问题。