事件处理程序影响 CLR 中的垃圾回收
Event handler affects in garbage collection in CLR
我对事件处理程序如何影响垃圾收集操作感到非常困惑。
例如,为什么对象a1没有被垃圾回收回收(a1的析构函数没有调用):
即使在取消订阅 timeChange 事件处理程序之后,垃圾收集器也不会调用析构函数。
此致。
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;
}
总结
造成这种情况的不是事件本身,而是使用闭包从长 运行ning 线程引用 class A 的实例成员。
事件本身不是问题,是吗?
此代码 a1.timeChange += A1_timeChange;
导致 class A 中实现事件 public event EventHandler timeChange
的委托引用 class B 中的 A1_timeChange
。
所以,参考是另一种方式
在您的场景中,如果您摆脱了对 class B 的所有引用,但没有取消订阅该事件,那么 A 中指向 B 中的处理程序方法的事件处理程序可以保持 class B 可访问, 因此没有 GC'ed
到底发生了什么
您的 class A 可从 GC 根之一访问(具体来说,主动 运行ning 线程),它仍然可以访问,因此未被收集 - read more
您使用此代码
生成了一个永久 运行ning 任务(当应用程序关闭/前台线程终止时它将停止)
Task.Factory.StartNew(() => {
while (true)
{
timeChange(DateTime.Now, null);
System.Threading.Thread.Sleep(3000);
}
事实是,您使用的是关闭 timeChange
事件的 lambda,这使编译器生成一个 class,它仅引用 class A
还有一件事,只要有一个析构函数(它被编译成一个终结器),你就可以通过一次 GC 收集来延长你的对象的生命周期——在第一次 GC 上,你的对象将被标记为不可访问,并且将放入终结队列。而在 next GC 上,finalizer 实际上会 运行 - read more
我对事件处理程序如何影响垃圾收集操作感到非常困惑。
例如,为什么对象a1没有被垃圾回收回收(a1的析构函数没有调用):
即使在取消订阅 timeChange 事件处理程序之后,垃圾收集器也不会调用析构函数。
此致。
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;
}
总结
造成这种情况的不是事件本身,而是使用闭包从长 运行ning 线程引用 class A 的实例成员。
事件本身不是问题,是吗?
此代码 a1.timeChange += A1_timeChange;
导致 class A 中实现事件 public event EventHandler timeChange
的委托引用 class B 中的 A1_timeChange
。
所以,参考是另一种方式
在您的场景中,如果您摆脱了对 class B 的所有引用,但没有取消订阅该事件,那么 A 中指向 B 中的处理程序方法的事件处理程序可以保持 class B 可访问, 因此没有 GC'ed
到底发生了什么
您的 class A 可从 GC 根之一访问(具体来说,主动 运行ning 线程),它仍然可以访问,因此未被收集 - read more
您使用此代码
生成了一个永久 运行ning 任务(当应用程序关闭/前台线程终止时它将停止)Task.Factory.StartNew(() => {
while (true)
{
timeChange(DateTime.Now, null);
System.Threading.Thread.Sleep(3000);
}
事实是,您使用的是关闭 timeChange
事件的 lambda,这使编译器生成一个 class,它仅引用 class A
还有一件事,只要有一个析构函数(它被编译成一个终结器),你就可以通过一次 GC 收集来延长你的对象的生命周期——在第一次 GC 上,你的对象将被标记为不可访问,并且将放入终结队列。而在 next GC 上,finalizer 实际上会 运行 - read more