3

我遇到了一个问题,我的程序在使用 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>();
            }
        }
    }
}

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

内存使用情况

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

插入的拦截器代理

现在,我想你可以通过以下方式解决这个问题

  1. 为整个应用程序使用全局(静态)容器,但目前这对我的应用程序不可行(我读到这是这样做的首选方式,不完全清楚为什么)
  2. ProxyGenerator使用静态并使用生成实例的方式自己生成代理UsingFactoryMethod(我现在这样做)

这给我留下了3个问题:

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

谢谢你。

4

3 回答 3

3

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

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

  • 容器针对这种情况进行了高度优化。通常使用 Reflection.Emit 生成委托,并缓存信息。这会产生一次性的性能影响(每个容器实例)并加速所有后续请求。为每个请求创建一个新实例会消耗应用程序的性能,因为所有这些反射和代码发射都会一次又一次地发生。
  • 但除了这种优化之外,注册过程本身也需要时间。这可能是一次性成本,但您会一遍又一遍地这样做。
  • 配置容器会变得更加困难。注册应该比请求更长的实例要困难得多。有一些方法可以解决这个问题,但这通常会导致容器配置难以掌握、难以维护并且存在错误。Castle Windsor 包含一个容器诊断功能,允许验证容器,但它不能进行跨容器验证。
于 2013-02-06T14:41:30.057 回答
1

我今天刚遇到同样的问题。要回答原始帖子中的 #3,性能计数器 [.NET Clr Loading -> Current Assemblies] 在运行您的代码片段时,由于加载了动态代理类型,它会显示出线性增加的程序集数量。

于 2015-08-19T19:10:31.290 回答
0

仔细阅读文档使拦截器总是瞬态的。

正确的代码是:

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>();
        }
    }
}
}
于 2013-02-07T11:34:01.627 回答