Preface: I know how to solve the problem. I want to know why it arises. Please read the question from top to bottom.
As we all (should) know, adding event handlers can cause memory leaks in C#. See Why and How to avoid Event Handler memory leaks?
On the other hand, objects often have similar or connected life cycles and deregistering event handlers is not necessary. Consider this example:
using System;
public class A
{
private readonly B b;
public A(B b)
{
this.b = b;
b.BEvent += b_BEvent;
}
private void b_BEvent(object sender, EventArgs e)
{
// NoOp
}
public event EventHandler AEvent;
}
public class B
{
private readonly A a;
public B()
{
a = new A(this);
a.AEvent += a_AEvent;
}
private void a_AEvent(object sender, EventArgs e)
{
// NoOp
}
public event EventHandler BEvent;
}
internal class Program
{
private static void Main(string[] args)
{
B b = new B();
WeakReference weakReference = new WeakReference(b);
b = null;
GC.Collect();
GC.WaitForPendingFinalizers();
bool stillAlive = weakReference.IsAlive; // == false
}
}
A
and B
reference each other implicitly via events, yet the GC can delete them (because it's not using reference counting, but mark-and-sweep).
But now consider this similar example:
using System;
using System.Timers;
public class C
{
private readonly Timer timer;
public C()
{
timer = new Timer(1000);
timer.Elapsed += timer_Elapsed;
timer.Start(); // (*)
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// NoOp
}
}
internal class Program
{
private static void Main(string[] args)
{
C c = new C();
WeakReference weakReference = new WeakReference(c);
c = null;
GC.Collect();
GC.WaitForPendingFinalizers();
bool stillAlive = weakReference.IsAlive; // == true !
}
}
Why can the GC not delete the C
object? Why does the Timer keep the object alive? Is the timer kept alive by some "hidden" reference of the timer mechanics (e.g. a static reference)?
(*) NB: If the timer is only created, not started, the issue does not occur. If it's started and later stopped, but the event handler is not deregistered, the issue persists.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…