匿名委托事件侦听器是否会阻止垃圾收集
本文关键字:是否 事件 侦听器 | 更新日期: 2023-09-27 17:49:18
我不确定在以下场景中是否能够垃圾收集子窗口。
- 用户控件包含"显示弹出窗口"命令
- 该命令创建一个子窗口,并为"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#和垃圾收集中的事件分离匿名侦听器
以下测试表明,不,该场景不会导致内存泄漏。
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
控件(持有对订阅者(DelegateCommand
(的引用,但不是相反的。因此,一旦ChildWindow
关闭,垃圾收集器就会释放其内存。