【问题标题】:Simple injector - decorators causing container to not be garbage collected?简单的注入器 - 导致容器不被垃圾收集的装饰器?
【发布时间】:2015-10-15 19:01:31
【问题描述】:

我注意到,当我通过简单的注入器添加装饰器时,容器不会超出范围。有谁知道这是否是预期的?如果我不添加装饰器,则容器将被垃圾收集。否则,它不是。我应该做些什么来强制清理?

这是一个简单的例子。如果添加了装饰器,则在“运行”完成后容器仍在内存中。如果没有添加装饰器,容器会被 GC'ed。

public interface IDoSomething { }
public class DoSomething: IDoSomething { }
public class DoSomethingDec1: IDoSomething {
    public DoSomethingDec1(IDoSomething handler) { }
}
public class DoSomethingDec2 : IDoSomething {
    public DoSomethingDec2(IDoSomething handler) { }
}

static void Main(string[] args) {
    Console.WriteLine("Press a key to start");
    Console.ReadKey(true);
    Run();
    GC.Collect();
    Console.WriteLine("Done");
    Console.ReadKey(true);
}

static void Run() {
    //can be re-created with 1 container; easier to see with multiple
    for (var i = 0; i < 1000; i++) {
        using (var container = new Container()) {
            container.Register<IDoSomething, DoSomething>();

            //Comment out these 2 lines to remove the decorators
            container.RegisterDecorator<IDoSomething, DoSomethingDec1>();
            container.RegisterDecorator<IDoSomething, DoSomethingDec2>();

            container.Verify();

            container.GetInstance<IDoSomething>();
        }
    }
}

使用装饰器:

没有装饰器:

【问题讨论】:

  • 为什么要创建多个容器实例?文档advices 创建单个容器实例并警告 创建“无限数量的容器实例”。
  • 嗨史蒂文,该示例创建多个以使其更容易发现。但是,这仅发生在一个容器中。我正在创建一个在内部使用简单注入器(单个容器)的库 - 我无法确定用户何时会处置我的根对象(其中包含 SI 容器)。这就是我注意到容器没有释放的原因。
  • 看来我们遇到了内存泄漏。我能够重现这一点。我还不清楚为什么这些实例会保持活动状态,但请放心,这不是故意的,是一个错误,我们会找到原因并修复此问题。
  • 但也就是说,在库中使用 DI 容器可能不是最佳选择。阅读 Mark Seemann 的 this excellent post 了解 DI 友好库。
  • 谢谢史蒂文。我会看看你链接的帖子。如果有什么不同的话,我对简单注入器的使用是一个实现细节。库本身没有直接指示正在使用 SI - 用户从不直接与其交互。

标签: c# memory-leaks dependency-injection simple-injector


【解决方案1】:

更新:此问题已在 v3.1.1 中修复。

问题是由 bug in the .NET framework 引起的,如果图形包含 ThreadLocal&lt;T&gt;,则循环对象图保持活动状态。在 Simple Injector 的情况下,装饰子系统将 ThreadLocal&lt;T&gt; 添加到 ContainerItems 字典中。 ThreadLocal 的值再次间接引用了Container,导致图形变为循环。由于 .NET 中的错误,ThreadLocal&lt;T&gt; 被认为是活动的,保持其依赖对象,例如 Container 活动。 Container 实例再次使其他所有内容保持活动状态,这显然会导致内存泄漏。

虽然我们可以等待 Microsoft 解决此问题,但这可能需要很长时间。所以我们的计划是在未来的补丁版本中解决这个问题。我们可能会用我们自己的不会导致内存泄漏的自定义实现替换 .NET 的 ThreadLocal&lt;T&gt;。此自定义实现已在 Simple Injector 的 PCL 库中使用,因为ThreadLocal&lt;T&gt; 不适用于 PCL。这意味着Simple Injector的PCL版本没有这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    相关资源
    最近更新 更多