我正在尝试理解事件如何导致内存泄漏。我在这个stackoverflow问题中找到了一个很好的解释,但是当我查看Windbg中的对象时,结果让我感到困惑。首先,我有一个简单的类如下。
class Person
{
public string LastName { get; set; }
public string FirstName { get; set; }
public event EventHandler UponWakingUp;
public Person() { }
public void Wakeup()
{
Console.WriteLine("Waking up");
if (UponWakingUp != null)
UponWakingUp(null, EventArgs.Empty);
}
}
现在我正在一个 Windows 窗体应用程序中使用这个类,如下所示。
public partial class Form1 : Form
{
Person John = new Person() { LastName = "Doe", FirstName = "John" };
public Form1()
{
InitializeComponent();
John.UponWakingUp += new EventHandler(John_UponWakingUp);
}
void John_UponWakingUp(object sender, EventArgs e)
{
Console.WriteLine("John is waking up");
}
private void button1_Click(object sender, EventArgs e)
{
John = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
MessageBox.Show("done");
}
}
正如您所看到的,我实例化了Person类并订阅了UponWakingUp事件。在这个表单上我有一个按钮。当用户点击此按钮时,我将此Person实例设置为null而没有取消订阅该事件。然后我调用GC.Collect以确保垃圾回收已完成。我在这里显示一个消息框,以便我可以附加Windbg来查找Form1类帮助和引用。在这个类中,我没有看到该事件的任何引用(Windbg输出如下,尽管Form1数据过长,我仅展示与我的问题相关的部分)。该类对Person类有引用,但它是null的。基本上,在我的看法中,这似乎不像是内存泄漏,因为Form1没有对Person类的任何引用,即使它没有取消订阅该事件。
我的问题是,这是否会导致内存泄漏。如果不是,为什么不是?
0:005> !do 0158d334
Name: WindowsFormsApplication1.Form1
MethodTable: 00366390
EEClass: 00361718
Size: 332(0x14c) bytes
File: c:\Sandbox\\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\WindowsFormsApplication1.exe
Fields:
MT Field Offset Type VT Attr Value Name
619af744 40001e0 4 System.Object 0 instance 00000000 __identity
60fc6c58 40002c3 8 ...ponentModel.ISite 0 instance 00000000 site
619af744 4001534 b80 System.Object 0 static 0158dad0 EVENT_MAXIMIZEDBOUNDSCHANGED
**00366b70 4000001 13c ...plication1.Person 0 instance 00000000 John**
60fc6c10 4000002 140 ...tModel.IContainer 0 instance 00000000 components
6039aadc 4000003 144 ...dows.Forms.Button 0 instance 015ad06c button1
0:008> !DumpHeap -mt 00366b70
Address MT Size
total 0 objects
Statistics:
MT Count TotalSize Class Name
Total 0 objects
John.UponWakingUp
包含对一个委托的引用,该委托包含对Form1
的引用。否则无法触发该事件。 - svick