c# - 为什么 Ninject 不使用 InCallScope 释放已处置的对象?

标签 c# .net-4.0 ninject ninject-extensions

我正在尝试在 WinForms 应用程序中使用 Ninject(版本 3.0.1),我有几个(当前)自绑定(bind)服务类,我使用 Ninject 构建它们。某些服务类需要其他服务类(子服务)。大多数这些服务类都需要一个存储库来与数据库交互,因为我有一个抽象的 IRepository 接口(interface)。我需要为服务类中的整个服务层次结构使用相同的存储库,所以我使用了 InCallScope()绑定(bind) IRepository 时的作用域。目前我正在使用 XPO 作为 ORM 工具,所以我有一个 XpoRepository 实现,我绑定(bind)到它。看我的other question关于这个场景。

我的绑定(bind)看起来像这样:

Bind<IRepository>().To<XpoRepository>().InCallScope();

我没有明确的 ToSelf()每个服务类的绑定(bind),所以我假设当我从 Ninject 获取它们时,它们应该具有 transient 范围,我将其解释为我必须手动处理它们。

假设我有一个 Services1 和一个 Services2 服务类,它们都有一个类型为 IRepository 的构造函数参数。现在假设 Services1 想使用 Services2 的一些方法,所以我向 Services1 添加了另一个构造函数参数,类型为 Services2。如果没有 Ninject,我会这样做:

var repo = new MyRepository(); // implementing IRepository
var service1 = new Services1(repo, new Services2(repo));

我在后台线程中使用其中一项服务(使用 TPL),循环如下:

while (true) {
    if (CancellatioPending())
        break;
    using (var service = _kernel.Get<Service1>())
    {
        // do some stuff using the service class
    }
    Thread.Sleep(20*1000);
}

在使用 Ninject 之前我有相同的结构,所以我(我认为)正确地实现了每个对象的处理,包括在正确位置的存储库。但是,我注意到,由于我为此使用了 Ninject,我的应用程序中存在大量内存泄漏,并且每 2-3 小时就会崩溃并出现 OutOfMemoryException。我在循环内放置了一个断点,并注意到 Ninject 缓存中有数千个条目充满了已处置的 XpoRepository 对象。我猜它们是由我处理的,但我不确定是谁调用了处理方法。

为什么 Ninject 持有这些废弃的对象?我希望当我在 using block (这是 IRepository 对象的范围,由于 InCallScope())的末尾处置主要服务时,其范围内的每个对象都应由 Ninject 处置和释放。

编辑:在对为什么这种模式不好发表任何评论或回答之前,我知道它可能会更好。我知道我可以提取服务接口(interface)以实际使用 DI 并提高可测试性,而且我也知道我可能应该使用 Func<IRepository>作为构造函数参数,并注入(inject)其中,这样每个服务都可以有自己的责任来处置存储库。只是我目前没有时间进行此类重构。

最佳答案

如果满足以下所有条件,Ninject 将发布存储库:

  • 没有人持有对 service1 的引用
  • service1 本身是 GC 的(因为你有一个 20 秒的线程 sleep ,所以它很可能被提升到 Gen 2 并且它们很少被释放)
  • 缓存修剪是在 service1 被 GC 之后执行的,缓存修剪间隔默认为 30 秒。您可能想尝试更短的间隔。
  • 对于上一点,您可以尝试通过在 service1 中实现 Ninject.Infrastructure.Disposal.INotifyWhenDisposed 来强制立即释放

关于c# - 为什么 Ninject 不使用 InCallScope 释放已处置的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17703718/

相关文章:

C# - 获取文件夹后代的 LastWriteTime

c# - 无法从 WP 8.1 中的音乐文件或文件夹中检索专辑封面

c# Excel Interop 等待处理 0x800AC472 错误的替代方法

c# - 如何将代理身份验证详细信息添加到 webclient 对象

c# - Application.GetContentStream 为内容 Uri 返回 null

.net-4.0 - .net 4.0 中的 parallel-for 是否自动获取 GPU 计算的特权?

.net - 如何避免.net的ZipPackage类中的[Content_Types] .xml

ninject - weakeventmessagebroker 和 messagebroker Ninject 扩展是否已弃用?

asp.net-mvc-5 - nuget中用于与WEB API集成的所有这些Ninject包是什么?

ninject继承接口(interface)