为什么把 Scoped 注入到 Singleton 会导致内存泄露? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
drymonfidelia
V2EX    程序员

为什么把 Scoped 注入到 Singleton 会导致内存泄露?

  •  
  •   drymonfidelia 307 天前 1617 次点击
    这是一个创建于 307 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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#的,别的有依赖注入的语言应该也一样。

    11 条回复    2024-12-11 17:54:26 +08:00
    crysislinux
        1
    crysislinux  
       307 天前 via Android
    我觉得没问题,又不会持续增长
    timethinker
        2
    timethinker  
       307 天前
    就你贴出的这个例子而言,是的,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 的实例,并且考虑了线程安全问题,那么这么做就没什么问题。
    cuso45h2o
        3
    cuso45h2o  
       307 天前
    DbContext 是只会创建一次,但是因为它不会被dispose ,如果它的代码有问题产生了大量 tracked entities ,这一个 DbContext 也会导致内存泄露。
    irisdev
        4
    irisdev  
       307 天前
    @cuso45h2o 楼主,请教个问题,如果像 op 这样写,后续请求造成的 changes 会 append 在这个单例的 dbcontext 上吗
    ch3nz
        5
    ch3nz  
       307 天前
    会“可能导致内存泄漏和行为异常”而不是“一定导致”
    你的例子是属于“一定导致”。
    比如你给数据库一顿操作,dbContext track 了所有数据库变化,本该释放,但是被 singleton 持有而不能释放。
    irisdev
        6
    irisdev  
       307 天前
    记得.net 不允许在 singleton 中引用 scope 吧,这么写不会报错吗
    cuso45h2o
        7
    cuso45h2o  
       307 天前 via iPhone   1
    回复#4 如果在 Singleton 里发生的更改会累积。
    #6 Microsoft.Extensions.DependencyInjection 会检测这种情况,如果把 scoped 注入到 Singleton 会报错 Cannot consume scoped service from singleton 。因为 OP 没说用的是什么 DI 接口,我假设 OP 自己实现了一个简易 DI ,这样注入会导致潜在的内存泄露的问题。
    @irisdev
    irisdev
        8
    irisdev  
       307 天前 via Android
    @cuso45h2o 明白了,谢谢解惑!
    liuliuliuliu
        9
    liuliuliuliu  
    PRO
       307 天前
    是的 楼上很多人都说了。
    所以.net 的默认 DI 不允许这么做……
    ltmst
        10
    ltmst  
       306 天前
    看到了这个例子,突然想起来知乎中一个回答说,ef 至今没有 "解决" 跨线程的 bug
    ne6rd
        11
    ne6rd  
       306 天前
    另外补充一点,一般不推荐在 Singleton 里用 Scoped 的类,但是非要用的话,也是有方法的。
    不能直接注入,但是可以注入一个 IServiceScopeFactory, CreateScope(), 然后 scope.ServiceProvider.GetServices<>();
    这个拿到的 Scoped 实例只能在 method 级别里访问,不能把它存到实例属性上给其他 method 共享。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2807 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 14:56 PVG 22:56 LAX 07:56 JFK 10:56
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86