GC.WaitForPendingFinalizers无法在异步方法中工作?

时间:2014-02-21 15:38:19

标签: c# wpf garbage-collection async-await

我有一些单元测试来验证使用WeakReferences的对象是否正常工作。在重构这些对象以异步工作后,单元测试失败。这似乎是由GC.WaitForPendingFinalizers在使用异步时无法工作(或工作方式不同?)引起的。

为了检查这一点,我创建了一个带有两个按钮的简单WPF应用程序,一个带有常规Click事件,另一个带有异步点击事件。

当我按下NormalGCTest按钮时,显示“对象垃圾收集:True”。

但是当我按下AsyncGCTest按钮时,会显示“对象垃圾收集:False”。

发生了什么事?有没有办法在我的测试中强制完整的垃圾收集?

    private void NormalGCTest(object sender, RoutedEventArgs e)
    {
        var temp1 = new object();
        var temp2 = new WeakReference(temp1);
        temp1 = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        temp1 = temp2.Target;
        System.Diagnostics.Debug.WriteLine("object garbage collected: {0}", temp1 == null);
    }

    private async void AsyncGCTest(object sender, RoutedEventArgs e)
    {
        var temp1 = new object();
        var temp2 = new WeakReference(temp1);
        temp1 = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        temp1 = temp2.Target;
        System.Diagnostics.Debug.WriteLine("object garbage collected: {0}", temp1 == null);
        await Task.Delay(0);
    }

1 个答案:

答案 0 :(得分:4)

对我而言,它已经正常工作了 - 我得到True / True。但是,您可以尝试一些方法来澄清正在发生的事情 - 例如:

var wr = CreateWeakReference();
Console.WriteLine("object available: {0}", wr.Target != null);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
Console.WriteLine("object garbage collected: {0}", wr.Target == null);

static WeakReference CreateWeakReference()
{
    return new WeakReference(new object());
}

这使用较少的本地,这可能会导致混淆,具体取决于编译器如何转换C#。它还使用了更具侵略性的GC.Collect

但重要的是:停止调用垃圾收集器。你几乎不应该这样做。最后的想法 - 你可能想避免async void。是的,我知道这是一个事件处理程序,但是一个很好的技巧就是立即调用非async void方法(必要时使用await)。