C# 简单的注入器装饰器导致容器不能被垃圾收集?

C# 简单的注入器装饰器导致容器不能被垃圾收集?,c#,memory-leaks,dependency-injection,simple-injector,C#,Memory Leaks,Dependency Injection,Simple Injector,我注意到,当我通过简单的注入器添加decorator时,容器不会超出范围。有人知道这是否是预期的吗?如果我不添加decorator,容器将被垃圾收集。否则,就不是了。我应该做些什么来强制清理 下面是一个简单的例子。如果添加了装饰器,则在“运行”完成后,容器仍在内存中。如果没有添加装饰器,容器将被GC'ed public interface IDoSomething { } public class DoSomething: IDoSomething { } public class DoSome

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

下面是一个简单的例子。如果添加了装饰器,则在“运行”完成后,容器仍在内存中。如果没有添加装饰器,容器将被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>();
        }
    }
}
公共接口{}
公共类DoSomething:IDoSomething{}
公共类DoSomethingDec1:IDOmething{
公共DoSomethingDec1(idosomethingHandler){}
}
公共类DoSomethingDec2:IDOmething{
公共DoSomethingDec2(IDoSomething处理程序){}
}
静态void Main(字符串[]参数){
Console.WriteLine(“按键启动”);
Console.ReadKey(true);
Run();
GC.Collect();
控制台。写入线(“完成”);
Console.ReadKey(true);
}
静态无效运行(){
//可以使用1个容器重新创建;使用多个容器更容易查看
对于(变量i=0;i<1000;i++){
使用(var container=newcontainer()){
container.Register();
//注释掉这两行以删除装饰器
container.RegisterDecorator();
container.RegisterDecorator();
container.Verify();
container.GetInstance();
}
}
}
与装饰师:

没有装饰师:


更新:此问题已在中修复

如果循环对象图包含
ThreadLocal
,则该问题是由使循环对象图保持活动状态的。对于简单的注入器,装饰器子系统将
ThreadLocal
添加到
容器的
字典中。
ThreadLocal
的值再次间接引用了
容器
,导致图形变为循环。由于.NET中的缺陷,
ThreadLocal
被认为是活动的,使其依赖对象(如
容器)保持活动状态。
容器
实例再次使其他所有内容保持活动状态,这显然会导致内存泄漏


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

为什么要创建多个容器实例?创建单个容器实例的文档,并警告不要创建“无限多个容器实例”。您好,Steven,该示例创建了多个容器实例,以便更容易发现。然而,这只发生在一个容器中。我正在创建一个在内部使用simple injector(单个容器)的库——我不能确定用户何时会处理我的根对象(包含SI容器)。这就是我注意到容器没有释放的原因。我们似乎有内存泄漏。我可以复制这个。我还不清楚为什么这些实例会保持活动状态,但请确保这不是故意的,这是一个bug,我们会找到原因并修复它。不过,在库中使用DI容器可能不是最佳选择。阅读Mark Seemann关于DI友好图书馆的文章。谢谢Steven。我会查看你链接的帖子。如果有什么不同的话,我对simple injector的使用就是一个实现细节。库本身没有给出SI正在使用的直接指示-用户从未直接与它交互。