匿名委托事件监听器是否会阻止垃圾回收?

时间:2012-12-21 23:44:16

标签: c# silverlight garbage-collection anonymous-delegates

我不确定在以下场景中是否可以对子窗口进行垃圾收集。

  1. 用户控件包含“show popup”命令
  2. 该命令创建一个子窗口,并为“已关闭”事件添加一个匿名侦听器。

  3. public partial class MainPage : UserControl
    {
        public ICommand PopupCommand { get; private set; }
    
        public MainPage()
        {
            InitializeComponent();
    
            PopupCommand = new DelegateCommand(arg => 
            {
                var child = new ChildWindow();
                child.Closed += (sender, args) =>
                {
                    MessageBox.Show("You closed the window!");
                };
                child.Show();
            });
        }
    }
    

    由于PopupCommand的委托表面上仍然包含对本地child变量的引用,每次调用PopupCommand是否会泄漏内存?或者垃圾收集器会以某种方式识别它在关闭后可以处置child吗?


    相关:detaching anonymous listeners from events in C# and garbage collection

1 个答案:

答案 0 :(得分:1)

以下测试表明,不,该方案不会导致内存泄漏。

public partial class LeakTest : UserControl
{
    public ICommand PopupCommand { get; private set; }

    public LeakTest()
    {
        InitializeComponent();

        PopupCommand = new DelegateCommand(arg =>
        {
            var child = new ChildWindow();
            child.Closed += (sender, args) =>
            {
                System.Diagnostics.Debug.WriteLine("Closed window");
            };

            // when the window has loaded, close it and re-trigger the command
            child.Loaded += (sender, args) =>
            {
                child.Close();
                PopupCommand.Execute(null);
            };
            child.Show();
        });
    }
}

(Winforms) post linked to by Jwosty的答案中提出了原因:

  

在您的示例中,发布者仅存在于私有方法的范围内,因此在方法返回后的某个时刻,对话框和处理程序都将被垃圾收集。

换句话说,内存泄漏问题实际上是相反的 - 事件发布者(ChildWindow控件)持有对订阅者的引用(DelegateCommand),但不是其他方式。因此,一旦ChildWindow关闭,垃圾收集器将释放其内存。