C# 闭包对垃圾回收器的奇怪影响

本文关键字:影响 闭包 | 更新日期: 2023-09-27 17:56:12

直接进入代码

class Program
{
    private static WeakReference<EventHandler<EventArgs>> _noClosure;
    private static WeakReference<EventHandler<EventArgs>> _closure;
    static void Main(string[] args)
    {
        Init();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        EventHandler<EventArgs> target;
        Console.WriteLine(_closure.TryGetTarget(out target));
        Console.WriteLine(_noClosure.TryGetTarget(out target));
    }
    class C { public void Go() { } }
    private static void Init()
    {
        _noClosure = new WeakReference<EventHandler<EventArgs>>((sender, args) =>
        {
        });
        var s = new C();
        _closure = new WeakReference<EventHandler<EventArgs>>((sender, args) =>
        {
              s.Go();
        });
    }
}

我从这段代码中得到的输出是

False
True

这到底是怎么回事?

附言我在试图弄清楚WeakEventManager是如何工作的时进入了这个。

C# 闭包对垃圾回收器的奇怪影响

编译器

会将_noClosure委托缓存在静态字段中,并在每次调用Init时重用它。完全相同的实例每次都可以重复使用。

将其与 _closure 进行比较,后者在每次调用 Init() 时关闭一个新的C()实例 - 无法缓存。

_noClosure缓存意味着存在对委托的强引用(字段),因此不能对其进行垃圾回收。

如果在应用程序上运行ildasm,则可以看到所有这些操作。