public class SingletonService
{
private readonly DbContext _dbContext;
public SingletonService(DbContext dbContext)
{
_dbContext = dbContext;
}
}
public class SomeController
{
private readonly SingletonService _singletonService;
private readonly DbContext _dbContext;
public SomeController(SingletonService singletonService, DbContext dbContext)
{
_singletonService = singletonService;
_dbContext = dbContext;
}
}
昨天晚上群里别人在讨论的问题,他们说这样注入会导致 SingletonService 里的 DbContext 释放不掉。我不是很理解,Singleton 每次运行都是同一个,SingletonService 里的 DbContext 永远只会创建一次,为什么会内存泄漏?
例子是 C#的,别的有依赖注入的语言应该也一样。
1
crysislinux 11 天前 via Android
我觉得没问题,又不会持续增长
|
2
timethinker 11 天前
就你贴出的这个例子而言,是的,DbContext 永远只会创建一次。
但是这种做法是有问题的,仅就这个例子而言,DbContext 不是线程安全的,这意味着当多个线程同时操作一个 DbContext 对象可能会引发数据竞争问题,破坏其内部状态的一致性。 微软官网是这样描述 DbContext 的生命周期的:The lifetime of a DbContext begins when the instance is created and ends when the instance is disposed. A DbContext instance is designed to be used for a single unit-of-work. This means that the lifetime of a DbContext instance is usually very short. 工作单元模式简单的来讲可以理解为对应于数据库的一个事务范围,在这个事务范围进行的操作会被追踪然后被提交。除非你确实有理由要一直保持一个 DbContext 的实例,并且考虑了线程安全问题,那么这么做就没什么问题。 |
3
cuso45h2o 11 天前
DbContext 是只会创建一次,但是因为它不会被 dispose ,如果它的代码有问题产生了大量 tracked entities ,这一个 DbContext 也会导致内存泄露。
|
5
ch3nz 11 天前
会“可能导致内存泄漏和行为异常”而不是“一定导致”
你的例子是属于“一定导致”。 比如你给数据库一顿操作,dbContext track 了所有数据库变化,本该释放,但是被 singleton 持有而不能释放。 |
7
cuso45h2o 11 天前 via iPhone 1
回复#4 如果在 Singleton 里发生的更改会累积。
#6 Microsoft.Extensions.DependencyInjection 会检测这种情况,如果把 scoped 注入到 Singleton 会报错 Cannot consume scoped service from singleton 。因为 OP 没说用的是什么 DI 接口,我假设 OP 自己实现了一个简易 DI ,这样注入会导致潜在的内存泄露的问题。 @irisdev |
9
nikenidage1 11 天前
是的 楼上很多人都说了。
所以.net 的默认 DI 不允许这么做…… |
10
gbw1992 10 天前
看到了这个例子,突然想起来知乎中一个回答说,ef 至今没有 "解决" 跨线程的 bug
|
11
ne6rd 10 天前
另外补充一点,一般不推荐在 Singleton 里用 Scoped 的类,但是非要用的话,也是有方法的。
不能直接注入,但是可以注入一个 IServiceScopeFactory, CreateScope(), 然后 scope.ServiceProvider.GetServices<>(); 这个拿到的 Scoped 实例只能在 method 级别里访问,不能把它存到实例属性上给其他 method 共享。 |