简单的注入器 - 导致容器不被垃圾收集的装饰器?
Simple injector - decorators causing container to not be garbage collected?
我注意到当我通过简单注入器添加装饰器时,容器不会超出范围。有谁知道这是否是预期的?如果我不添加装饰器,容器就会被垃圾回收。否则,它不是。有什么我应该做的来强制清理吗?
这是一个简单的例子。如果添加装饰器,容器在 'Run' 完成后仍在内存中。如果不添加装饰器,容器将被 GC 处理。
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>();
}
}
}
有装饰器:
没有装饰器:
更新:此问题已在 v3.1.1.
中修复
问题是由 引起的,如果图包含 ThreadLocal<T>
,它会使循环对象图保持活动状态。在 Simple Injector 的情况下,装饰器子系统将 ThreadLocal<T>
添加到 Container
的 Items
字典中。 ThreadLocal
的值再次间接引用 Container
,导致图形变为循环。由于 .NET 中的错误,ThreadLocal<T>
被认为是活动的,保持其依赖对象,例如 Container
活动。 Container
实例再次使其他一切保持活动状态,这显然会导致内存泄漏。
尽管我们可以等待 Microsoft 修复此问题,但这可能需要很长时间。所以我们的计划是在未来的补丁版本中解决这个问题。我们可能会将 .NET 的 ThreadLocal<T>
替换为我们自己的不会导致内存泄漏的自定义实现。此自定义实现已在 Simple Injector 的 PCL 库中使用,因为 ThreadLocal<T>
不适用于 PCL。这意味着 PCL 版本的 Simple Injector 没有这个问题。
我注意到当我通过简单注入器添加装饰器时,容器不会超出范围。有谁知道这是否是预期的?如果我不添加装饰器,容器就会被垃圾回收。否则,它不是。有什么我应该做的来强制清理吗?
这是一个简单的例子。如果添加装饰器,容器在 'Run' 完成后仍在内存中。如果不添加装饰器,容器将被 GC 处理。
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>();
}
}
}
有装饰器:
没有装饰器:
更新:此问题已在 v3.1.1.
中修复问题是由 ThreadLocal<T>
,它会使循环对象图保持活动状态。在 Simple Injector 的情况下,装饰器子系统将 ThreadLocal<T>
添加到 Container
的 Items
字典中。 ThreadLocal
的值再次间接引用 Container
,导致图形变为循环。由于 .NET 中的错误,ThreadLocal<T>
被认为是活动的,保持其依赖对象,例如 Container
活动。 Container
实例再次使其他一切保持活动状态,这显然会导致内存泄漏。
尽管我们可以等待 Microsoft 修复此问题,但这可能需要很长时间。所以我们的计划是在未来的补丁版本中解决这个问题。我们可能会将 .NET 的 ThreadLocal<T>
替换为我们自己的不会导致内存泄漏的自定义实现。此自定义实现已在 Simple Injector 的 PCL 库中使用,因为 ThreadLocal<T>
不适用于 PCL。这意味着 PCL 版本的 Simple Injector 没有这个问题。