C# 在BeginLifetimeScope配置中使用RegisterInstance会导致内存泄漏

C# 在BeginLifetimeScope配置中使用RegisterInstance会导致内存泄漏,c#,memory-leaks,autofac,C#,Memory Leaks,Autofac,我对Autofac有以下用法 公共类执行器 { 私有只读ILifetimeScope根范围; 公共执行器(ILifetimeScope根范围) { this.rootScope=rootScope; } 公共异步任务ExecuteAsync(IData数据) { 使用(ILifetimeScope childScope=this.rootScope.BeginLifetimeScope)(生成器=> { var模块=新的ExecutionModule(数据); 生成器注册表模块(模块); }))

我对Autofac有以下用法

公共类执行器
{
私有只读ILifetimeScope根范围;
公共执行器(ILifetimeScope根范围)
{
this.rootScope=rootScope;
}
公共异步任务ExecuteAsync(IData数据)
{
使用(ILifetimeScope childScope=this.rootScope.BeginLifetimeScope)(生成器=>
{
var模块=新的ExecutionModule(数据);
生成器注册表模块(模块);
}))
{
//解决依赖IData的服务并完成工作
}
}
}
公共类ExecutionModule:模块
{
私有只读IData数据;
公共执行模块(IData数据)
{
这个数据=数据;
}
受保护的覆盖无效负载(ContainerBuilder builder)
{
builder.RegisterInstance(this.data).As();
}
}
ExecuteAsync
在应用程序运行时被多次调用,
IData
表示来自外部的输入(对于每个
ExecuteAsync
),应该与生存期范围内的服务共享

运行应用程序一段时间后,我开始感到内存耗尽。后来通过额外的评测,我确定
IData
的实例在垃圾收集中幸存下来,并且似乎导致了内存泄漏

作为实验,从代码中删除了
ExecutionModule
(即
RegisterInstance
)的注册,并消除了内存泄漏

Autofac的代码对
BeginLifetimeScope
很有意思:

///子作用域中注册的组件将被视为
///在根作用域中注册,即SingleInstance()组件将与
///作为根范围。

问题是:如果
RegisterInstance
意味着注册singleton,那么在这种情况下,
IData
的实例将与根作用域一样存在,即使它们只能在注册的
childScope
内解决,我说得对吗?

我认为这条评论可能需要重新审视和修正。自从添加到
ILifetimeScope
界面以来(看起来像是六年?),在过去的几年里发生了很多变化,虽然内部结构发生了变化,但界面没有发生变化,因此文档没有被重新访问

下面是我使用Autofac 6运行的一个快速测试:

使用系统;
使用Autofac;
使用Autofac.Diagnostics;
名称空间AutofacDemo
{
公共静态类程序
{
公共静态void Main()
{
var builder=new ContainerBuilder();
builder.RegisterType().SingleInstance();
使用var container=builder.Build();
var dep=container.Resolve();
WriteLine(“在根作用域中注册为单个实例的依赖关系:”);
WriteLine(“ID:{0}”,dep.ID);
WriteLine(“范围标记:{0}”,dep.ScopeTag);
Console.WriteLine();
var rootScopeTag=dep.ScopeTag;
使用var standaloneScope=container.BeginLifetimeScope();
dep=标准镜。解析();
WriteLine(“在根目录中注册的依赖项,在子范围中解析:”);
WriteLine(“ID:{0}”,dep.ID);
WriteLine(“范围标记:{0}”,dep.ScopeTag);
WriteLine(“从根?{0}解析”,dep.ScopeTag==rootScopeTag);
Console.WriteLine();
使用var singleInstanceScope=container.BeginLifetimeScope(
b=>b.RegisterType()
.SingleInstance());
dep=singleInstanceScope.Resolve();
WriteLine(“在子作用域中注册为单个实例的依赖关系:”);
WriteLine(“ID:{0}”,dep.ID);
WriteLine(“范围标记:{0}”,dep.ScopeTag);
WriteLine(“从根?{0}解析”,dep.ScopeTag==rootScopeTag);
Console.WriteLine();
var instance=new Dependency();
使用var registerInstanceScope=container.BeginLifetimeScope(
b=>b.RegisterInstance(实例)
.OnActivating(e=>e.Instance.ScopeTag=e.Context.Resolve().Tag));
dep=registerInstanceScope.Resolve();
WriteLine(“在子作用域中注册为实例的依赖关系:”);
WriteLine(“ID:{0}”,dep.ID);
WriteLine(“范围标记:{0}”,dep.ScopeTag);
WriteLine(“从根?{0}解析”,dep.ScopeTag==rootScopeTag);
}
}
公共类依赖关系
{
公共依赖性()
{
this.Id=Guid.NewGuid();
}
公共依赖项(ILifetimeScope范围)
:此()
{
this.ScopeTag=scope.Tag;
}
公共Guid Id{get;}
公共对象范围标记{get;set;}
}
}
这样做的目的是尝试几种方法来解析
.SingleInstance()
.RegisterInstance()
组件,并显示它们实际上来自哪个范围。它通过将
ILifetimeScope
注入构造函数来实现这一点,您将始终获得组件解析的生存期范围。此操作的控制台输出如下所示:

Dependency registered as single instance in root scope:
ID: 056e1584-fa2a-4657-b58c-ccc8bfc504d2
Scope tag: root

Dependency registered in root, resolved in child scope:
ID: 056e1584-fa2a-4657-b58c-ccc8bfc504d2
Scope tag: root
Resolved from root? True

Dependency registered as single instance in child scope:
ID: 3b410502-b6f2-4670-a182-6b3eab3d5807
Scope tag: System.Object
Resolved from root? False

Dependency registered as instance in child scope:
ID: 20028683-23c1-48a0-adbe-94c3a8180ed7
Scope tag: System.Object
Resolved from root? False
.SingleInstance()
生存期范围项目将始终从其注册的生存期范围中解析。这会阻止你制造一个奇怪的问题。在前两个解析操作中,您会注意到这一点-从根容器和嵌套范围解析都会显示范围标记是
root
scope标记,因此我们知道在这两种情况下它都来自容器

RegisterInstance
没有依赖项,因为它是构造的,但我通过添加一个激活的
处理程序来模拟该功能。在本例中,我们看到对象实际上得到了解析