Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# GC.WaitForPendingFinalizers不在异步方法中工作?_C#_Wpf_Garbage Collection_Async Await - Fatal编程技术网

C# GC.WaitForPendingFinalizers不在异步方法中工作?

C# GC.WaitForPendingFinalizers不在异步方法中工作?,c#,wpf,garbage-collection,async-await,C#,Wpf,Garbage Collection,Async Await,我有一些单元测试来验证使用weakreference的对象是否正常工作。重构这些对象以异步工作后,单元测试失败。这似乎是由于使用异步时GC.WaitForPendingFinalizers不工作(或工作方式不同?)造成的 为了检查这一点,我创建了一个简单的WPF应用程序,其中有两个按钮,一个是常规单击事件,另一个是异步单击事件 当我按下NormalGCTest按钮时,会显示“对象垃圾收集:True” 但当我按下AsyncGCTest按钮时,会显示“对象垃圾收集:False” 发生了什么事?有没有

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

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

当我按下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);
    }

对我来说,它已经很好用了——我得到了
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);

这会使用更少的局部变量,这可能会导致混淆,具体取决于编译器如何翻译C#。它还使用更具攻击性的
GC.Collect


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

对我来说,它已经可以正常工作了-我得到
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);

这会使用更少的局部变量,这可能会导致混淆,具体取决于编译器如何翻译C#。它还使用更具攻击性的
GC.Collect


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

可能出于某种原因,生成的闭包类仍然引用temp1。我不知道async/await可能保证的任何GC属性。当然,C语言不能保证在调用Collect时temp1是死的。不建议显式调用GC。你确定你需要它吗?顺便说一句,AFAIK GC可以跨所有线程工作(在清理时停止所有线程)。将它与async结合使用感觉有点奇怪。在控制台应用程序中,两者都适用于我。。。您正在调试器下运行吗?这可能会有所不同。在本地运行它,我会得到
True
True
-它会同时被收集ways@PetarRepac这是一个涉及弱引用的单元测试,因此当然需要调用GC。我不认为它是在实际的代码中调用的。可能出于某种原因,生成的闭包类仍然有对temp1的引用。我不知道async/await可能保证的任何GC属性。当然,C语言不能保证在调用Collect时temp1是死的。不建议显式调用GC。你确定你需要它吗?顺便说一句,AFAIK GC可以跨所有线程工作(在清理时停止所有线程)。将它与async结合使用感觉有点奇怪。在控制台应用程序中,两者都适用于我。。。您正在调试器下运行吗?这可能会有所不同。在本地运行它,我会得到
True
True
-它会同时被收集ways@PetarRepac这是一个涉及弱引用的单元测试,因此当然需要调用GC。我不认为它是在实际的代码中调用的。关于你最后的评论:我完全知道它的缺点。我仅在单元测试中使用GC.Collect(),异步void用于简化示例。将对象创建放在静态方法中解决了问题(也在我的单元测试中)。@MarcelW那么它几乎肯定与编译器选择如何处理局部变量(包括编译器引入的瞬态局部变量)有关将方法转换为状态机时(局部变量变为字段)。因此,不同的编译器(或不同的编译器选项)可能会有不同的结果。我仅在单元测试中使用GC.Collect(),异步void用于简化示例。将对象创建放在静态方法中解决了问题(也在我的单元测试中)。@MarcelW那么它几乎肯定与编译器选择如何处理局部变量(包括编译器引入的瞬态局部变量)有关将方法转换为状态机时(局部变量变为字段)。因此,不同的编译器(或不同的编译器选项)可能会有不同的结果。