我对事件处理程序如何影响垃圾收集操作感到困惑。
例如,为什么对象a1没有被垃圾收集收集(a1的析构函数没有调用):
即使在取消订阅timeChange eventHandler之后,析构函数也不会被垃圾收集器调用。
最好的问候。
public class B
{
private void button1_Click(object sender, EventArgs e)
{
A a1 = new A();
a1.timeChange += A1_timeChange;
a1.Start();
a1 = null;
GC.Collect();
}
private void A1_timeChange(object sender, EventArgs e)
{
MessageBox.Show(((DateTime)sender).ToString() );
}
}
public class A
{
~A()
{
MessageBox.Show("A Collected");
}
public void Start()
{
if (timeChange != null)
{
Task.Factory.StartNew(() => {
while (true)
{
timeChange(DateTime.Now, null);
System.Threading.Thread.Sleep(3000);
}
});
}
}
public event EventHandler timeChange;
}
答案 0 :(得分:1)
总结
事件本身不是导致这种情况,而是使用闭包来从长时间运行的线程引用类A的实例成员。
事件本身不是问题,或者是它?
此代码a1.timeChange += A1_timeChange;
导致类A中的委托实现事件public event EventHandler timeChange
以引用类B中的A1_timeChange
。
因此,引用是其他方式
在你的场景中,如果你摆脱了对B类的所有引用,但没有取消订阅该事件,那么A中指向B中的处理程序方法的事件处理程序可以保持B类可达,因此不是GC'编
真实情况
您的A类可以从其中一个GC根(特别是主动运行的线程)访问,它仍然可以访问,因此不会被收集 -
使用此代码生成了一个永久运行的任务(当应用程序关闭/前台线程终止时它会停止)
Task.Factory.StartNew(() => {
while (true)
{
timeChange(DateTime.Now, null);
System.Threading.Thread.Sleep(3000);
}
问题是,您正在使用关闭timeChange
事件的lambda,这使得编译器生成一个只引用A类的类
还有一件事,就是通过一个descructor(编译成终结器),你可以通过一个GC集合延长对象的生命周期 - 在第一个GC上,你的对象将被标记为无法访问,并将被放到终结队列。在 next GC上,终结器将实际运行 - read more