IDisposable接口确认

IDisposable interface confirmation

我们已经广泛阅读了这篇文章:

https://autofaccn.readthedocs.io/en/latest/lifetime/disposal.html?highlight=Dispose

而且我们了解范围和外部拥有的功能。 我已经阅读了一些帖子,但仍然不确定一件事,只需要确认一下。

我有一个实现 IDisposable 的 DisposableClass 和一个 NotDisposableClass。

给定以下代码:


        private IContainer _container;
        private ILifetimeScope _scope1;
        private ILifetimeScope _scope2;

        public Form1()
        {
            InitializeComponent();

            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<DisposableClass>();
            builder.RegisterType<NotDisposableClass>();
            _container = builder.Build();
        }

        // Case 1: When finished, only coso2 is cleaned from memory.
        private void Case1()
        {
            DisposableClass coso1 = _container.Resolve<DisposableClass>();
            coso1.DoSomething();
            
            NotDisposableClass coso2 = _container.Resolve<NotDisposableClass>();
            coso2.DoSomething();
        }

        // Case 2: When finished, only coso2 is cleaned from memory.
        private void Case2()
        {
            DisposableClass coso1 = _container.Resolve<DisposableClass>();
            coso1.DoSomething();
            coso1.Dispose();
            
            NotDisposableClass coso2 = _container.Resolve<NotDisposableClass>();
            coso2.DoSomething();
        }

        // Case 3: Both coso1 and coso2 are released from memory.
        private void Case3()
        {
            using (var scope = _container.BeginLifetimeScope())
            {
                DisposableClass coso1 = scope.Resolve<DisposableClass>();
                coso1.DoSomething();
                coso1.Dispose();
            
                NotDisposableClass coso2 = scope.Resolve<NotDisposableClass>();
                coso2.DoSomething();
            }
        }

        // Case4: Both coso1 and coso2 are released.
        private void Case4()
        {
            _scope1 = _container.BeginLifetimeScope();
            DisposableClass coso1 = _scope1.Resolve<DisposableClass>();
            coso1.DoSomething();
            coso1.Dispose();
            
            _scope2 = _container.BeginLifetimeScope();
            NotDisposableClass coso2 = _scope2.Resolve<NotDisposableClass>();
            coso2.DoSomething();

            _scope1.Dispose();
        }

我没想到 Case1 和 Case2 的结果,这些结果在广泛使用 autofac 的更复杂的应用程序中导致了巨大的内存泄漏问题。 当 class 实现 IDisposable(案例 1)时,甚至在处理它(案例 2)时,团队中没有人期望容器可以维护对非作用域变量的引用。

注册为 ExternallyOwned 并不是真正的解决方案,因为注册类型的模块并不真正知道该类型将如何、何时或何地使用,除了那些单例工厂。这意味着每个模块都应该将所有类型注册为 ExternallyOwned,这就像删除了一半的 autofac 功能。

使用生命周期范围是事务操作、web api 和小型生命周期操作的一个很好的解决方案,但在很多情况下它的用法不是很漂亮。假设您有一系列周期性循环的项目,每一步都需要创建一个 Disposable 对象的新实例。为此,我们使用实际上位于顶级构建器范围内的 SingleInstanceFactories。我们注意到,即使您关闭了创建此序列的 window,即使在调用 Dispose 时也不会真正从内存中释放该工厂使用容器 Resolve 创建的每个项目。

我们讨论了可能的解决方案,我们想出了一个新的范围,每个创建请求传递给每个工厂,并存储这个范围以及请求的实例,但这似乎有很多工作。因为你必须在字典中管理所有使用的范围以及请求它属于哪个实例。

对我来说,当变量的范围被释放时,即 Case1 和 Case2 的情况,变量应该像 .NET 框架自己做的那样被释放(在所有情况下释放 coso2 的方式相同).或者至少,请注意,在 case2 中,我们将 Dispose() 强制为 InsntancePerDependency 对象实例,然后将其从内存中释放。

无论你强制GC多少次,变量都不会从内存中释放,直到你处理容器,这在前端应用程序中是不容易处理的。

总结一下:

根据我看到的结果和关于您如何执行测试的缺失代码,我很确定问题出在您的测试设置上,而不是 Autofac。他们的文档中关于 Automatic Disposal 的讨论明确指出:

You can then register your component as needed and at the end of each lifetime scope in which the component is resolved, the Dispose() method on the component will be called.

Form1 的生命周期不受 AutoFac 控制(我假设),因此它不知道何时自动释放对象。在案例 3 + 4 中,你告诉它生命周期结束的时间,这样它就可以正确地处理对象。

tl;dr 损坏的测试设置和对组件寿命的不了解会导致意外结果。

为了完成,我将回答我已经知道的问题。

阅读以下内容非常有帮助link: https://nblumhardt.com/2011/01/an-autofac-lifetime-primer/

  • 案例 1 和案例 2 是 Autofac 中对象处理的预期行为吗?还是错误?

这是 Autofac 的正常行为。 Aufofac 将持有对其创建的任何 IDisposable 实例的引用,因此 GC 将不会释放该资源,直到该范围内的 autofac 容器被释放。 意识到这一点很重要,因为您可能认为 Net 框架将释放这些变量,因为它们在代码中的范围已经结束。 另一方面,如果 Autofac 能够注意到它是否是唯一持有对实例的引用并释放它的,这可能是一个很好的功能。

  • 有没有办法告诉容器释放资源而不释放资源?或者它创建的特定实例?

无法强制释放容器创建的特定实例。 唯一可用的选项是遵循建议,在任何容器解析调用之前使用 BeginLifeTimeScope 并以某种方式保存对生命周期范围的引用以在需要时释放它。

不过,这可能也是一个不错的功能。

感谢您的回答,如果文本的某些部分不够直接,我们深表歉意。