简体   繁体   English

Castle Windsor Interceptor内存泄漏

[英]Castle Windsor Interceptor memory leak

I ran into a problem where my program would run out of memory when using Castle Windsor and interceptors. 我遇到了一个问题,当使用Castle Windsor和拦截器时,我的程序会耗尽内存。 It's reproducible 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: 这就是内存使用的发展方式:

内存使用情况

So the thing that threw me off was that I thought there was a non-managed code memory leak, but after a lot of debugging I found out the problem was with the interceptor prxoy generation: a new (dynamic) assembly with a proxy type is introduced to the runtime everytime it's resolved: 所以让我失望的是我认为有一个非托管代码内存泄漏,但经过大量调试我发现问题出在拦截器prxoy生成:一个带代理类型的新(动态)程序集是每次解决时都会引入运行时:

拦截代理插入

Now, I guess you can solve this by 现在,我想你可以解决这个问题

  1. using a global (static) container for the entire app, but at the moment this is not feasible for my app (I read this is the preferred way of doing this, not entirely clear why) 为整个应用程序使用全局(静态)容器,但目前这对我的应用程序来说是不可行的(我读过这是执行此操作的首选方式,并不完全清楚原因)
  2. generating the proxy yourself using a static ProxyGenerator and using the UsingFactoryMethod way of producing an instance (which I do now) 使用静态ProxyGenerator自己生成代理并使用UsingFactoryMethod生成实例的方式(我现在这样做)

This leaves me to 3 questions: 这让我有3个问题:

  1. Am I using Castle Windsor correctly (docs are not entirely clear) and if so is there a way for Castle Windsor to cache the proxy type? 我是否正确使用Castle Windsor(文档并不完全清楚)如果有的话,Castle Windsor是否有办法缓存代理类型?
  2. Should Castle Windsor cache the proxy type automatically (or: is the current behavior a bug)? Castle Windsor应该自动缓存代理类型(或者:当前行为是一个错误)吗?
  3. How would you debug (using perfmon, for example) that dynamically generated assemblies are eating all your memory? 您将如何调试(例如使用perfmon)动态生成的程序集正在占用您的所有内存?

Thank you. 谢谢。

I read this is the preferred way of doing this, not entirely clear why 我读过这是这样做的首选方式,并不完全清楚原因

Having one single container for the lifetime of the application is preferred, because: 在应用程序的生命周期内拥有一个容器是首选,因为:

  • Containers are highly optimized for this scenario. 容器针对此方案进行了高度优化。 Often generation of delegates using Reflection.Emit and information is cached. 通常使用Reflection.Emit和信息生成代理。 This gives a one-time performance hit (per container instance) and speeds up all following requests. 这样可以获得一次性性能(每个容器实例)并加快所有后续请求。 Creating a new instance per request can drain the performance of your application, since all this reflection and code emitting is happing again and again. 为每个请求创建一个新实例可能会耗尽应用程序的性能,因为所有这些反射和代码发出都是一次又一次的骚扰。
  • But besides this optimization, the registration process itself takes time. 但除了这种优化之外,注册过程本身也需要时间。 This could be a one-time cost, but you're doing it over and over again. 这可能是一次性费用,但你一遍又一遍地做。
  • Configuring the container can become much harder. 配置容器会变得更加困难。 Registering instances that should outlive the the request are are much harder. 注册应该比请求更长的实例要困难得多。 There are ways around this, but this will often lead to a container configuration that is hard to grasp, hard to maintain and has bugs. 有很多方法,但这通常会导致容器配置难以掌握,难以维护并且存在错误。 Castle Windsor contains a container diagnostics feature that allows to verify the container, but it can't do cross-container verification. Castle Windsor包含容器诊断功能 ,可以验证容器,但不能进行跨容器验证。

I just ran into this same issue today. 我今天刚遇到同样的问题。 To answer #3 from the original post, the performance counter [.NET Clr Loading -> Current Assemblies] would have shown a linearly increasing number of assemblies when running your snippet of code due to the dynamic proxy types being loaded. 要回答原始帖子中的#3,由于加载了动态代理类型,性能计数器[.NET Clr加载 - >当前程序集]在运行代码片段时会显示线性增加的程序集数量。

Read the documentation carefuly. 仔细阅读文档 Make interceptors always transient. 使拦截器始终是瞬态的。

Correct code is: 正确的代码是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM