2

我不确定在以下情况下是否能够对子窗口进行垃圾收集。

  1. 用户控件包含“显示弹出”命令
  2. 该命令创建一个子窗口,并为“Closed”事件添加一个匿名侦听器。

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在关闭后处理吗?


相关:从 C# 中的事件和垃圾收集中分离匿名侦听器

4

1 回答 1

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();
        });
    }
}

原因在Jwosty 链接到的(Winforms)帖子的答案中提出:

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

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

于 2012-12-22T00:05:42.023 回答