You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决C#中IDisposable对象循环Dispose的栈溢出问题

如何避免循环依赖的IDisposable对象释放时出现无限递归?

当两个存在循环依赖的IDisposable对象需要互相传播释放操作时,如何避免Dispose()方法因无限递归引发StackOverflowException?

我初步设想通过标记对象是否正在释放来提前退出,并实现了如下示例代码:

using CircularDispose;
using JetBrains.Annotations;

Example a = new(nameof(a));
Example b = new(nameof(b));

a.Other = b;
b.Other = a;

Console.WriteLine("Start");

a.Dispose();

Console.WriteLine($"{nameof(a)} is disposed: {a.IsDisposed}");
Console.WriteLine($"{nameof(b)} is disposed: {b.IsDisposed}");

Console.WriteLine("Finished");

namespace CircularDispose
{
    [PublicAPI]
    public class Example : IDisposable
    {
        private bool _isDisposing;
        private string _name;

        public Example? Other { get; set; }

        public bool IsDisposed { get; private set; }

        public Example(string name) => _name = name;

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }

        private void Dispose(bool disposing)
        {
            Console.WriteLine($"{_name}.{nameof(Dispose)}({disposing}) was called");

            if (!_isDisposing && !IsDisposed)
            {
                _isDisposing = true;

                if (disposing)
                {
                    DisposeManagedResources();
                }

                DisposeUnmanagedResources();

                IsDisposed = true;
            }
        }

        ~Example()
        {
            Dispose(false);
        }

        [PublicAPI]
        protected virtual void DisposeUnmanagedResources()
        {
            // dispose unmanaged resources
        }

        [PublicAPI]
        protected virtual void DisposeManagedResources()
        {
            Other?.Dispose();
            Other = null;
        }
    }
}

程序输出为:

Start
a.Dispose(True) was called
b.Dispose(True) was called
a.Dispose(True) was called
a is disposed: True
b is disposed: True
Finished

但我未在快速搜索中找到同类实现,因此想确认该方案是否安全可行。


你的方案是安全可行的,核心思路通过_isDisposing标记避免重复进入释放逻辑,完美解决了循环依赖下的递归问题。

具体逻辑分析:

  • 调用a.Dispose()后,a的_isDisposing被设为true,随后触发b.Dispose();
  • b进入释放流程后同样标记自身_isDisposing为true,再调用a.Dispose();
  • 此时a的_isDisposing已为true,直接跳过核心释放逻辑,终止了递归循环;
  • 最终两个对象都会完成完整的释放流程,IsDisposed均被正确设置为true。

额外优化建议:

  • 如果你的对象会在多线程环境中被调用释放,建议给_isDisposing和IsDisposed添加volatile修饰,确保线程间的可见性;
  • 当前实现中DisposeManagedResources最后将Other设为null的操作很合理,能帮助GC更快识别可回收对象,减少内存占用。

内容的提问来源于stack exchange,提问作者michi-b

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 21:12:09