IServiceProvider 垃圾收集/处理

Dmy*_*tov 5 c# memory-leaks .net-core

我试图在我的应用程序中调试内存泄漏(请参阅相关问题)并且遇到了一个微笑错误的行为。

在这段代码中(当然是简化的片段):

    while (true)
    {
        using (var context = _serviceProvider.GetRequiredService<IDataContext>())
        {
            Console.WriteLine("Hello");
        }
    }
Run Code Online (Sandbox Code Playgroud)

内存消耗快速增长

如果我注释掉 service spawn,内存消耗是稳定的。

    while (true)
    {
        // using (var context = _serviceProvider.GetRequiredService<IDataContext>())
        // {
            Console.WriteLine("Hello");
        // }
    }
Run Code Online (Sandbox Code Playgroud)

服务已注册为瞬态

我的理解是using声明负责处理服务。var context在 范围内创建,while并且应该在新迭代开始时销毁。

我的第一个想法是 GC 只是没有足够频繁地完成它的工作,但是当消耗的内存量增加时频率不会增加?

为什么我错了?

Dmy*_*tov 9

经过几天的斗争,我终于得出了答案。简而言之,问题在于 Microsoft DI 容器不处理瞬态服务,而是保留对它们的引用。

这是github上的相应问题

开发人员不打算修复它,因为修复的成本(复杂性和黑客性)超过了收益。

建议的解决方法是使用范围服务而不是临时服务。

这是一个示例代码,请参阅issue 中的更多内容。

using (var scope = serviceProvider.CreateScope())
using (var context = scope.ServiceProvider.GetRequiredService<IDataContext>())
{ ... }
Run Code Online (Sandbox Code Playgroud)


小智 5

只是想指出,从瞬态服务切换到范围服务可能还不够。在我的应用程序中,根本不需要。

\n\n

我的问题是,正如您在回答中已经说过的,ServiceProvider会跟踪它创建的所有对象。\n长时间运行的应用程序和从未释放的容器会导致巨大的内存消耗。即使容器仅创建快速运行“超出范围”的瞬态对象(甚至不是 IDisposable)。由于 ServiceProvider 仍在跟踪这些对象,因此 GC 无法完成其工作。

\n\n

考虑按照建议使用作用域 ServiceProvider,因为处置它也会结束其所有子项(作用域和瞬态)的生命周期。\nDon\xe2\x80\x99t 让容器(子项)超出范围。即使对于瞬态对象也可以使用作用域 ServiceProvider。

\n


归档时间:

查看次数:

2439 次

最近记录:

6 年,2 月 前