c# - 调试版本中带有垃圾收集的奇怪触发的奇怪错误

标签 c# .net debugging garbage-collection

我在编写垃圾收集测试时偶然发现了一组在 Debug模式下出现的奇怪错误。 这是经过提炼的 POC 代码。 有一个包含 20 个 lambda 的列表和一个对它们的弱引用列表。 我访问第 13 个 lambda(调用 .ToString()),然后清除列表。 然后强制垃圾收集并分析哪些元素在清理后幸存下来。

    public void TestGC_WTF() {
        var handlers = new List<Action>();
        var weakReferences = new List<WeakReference>();

        int testValue = 0;
        for (int i = 0; i < 20; i++) {
            int number = i;
            Action handler = () => testValue += number;
            handlers.Add(handler);
            weakReferences.Add(new WeakReference(handler));
            handler = null;
        }

        handlers[13].ToString();

        handlers.Clear();

        GC.Collect();

        if (false) { } //This is required for the bug to occur.

        var aliveReferences = Enumerable.Range(0, weakReferences.Count).Where(i => weakReferences[i].IsAlive).ToArray();
        Console.WriteLine("Uncollected handlers: {0}", string.Join(",", aliveReferences));
    }

在 Debug模式下,此代码打印(“未收集的处理程序:13,19”。 我对这个结果的问题如下:

  1. 第 19 个元素未被收集(即使我在每次循环迭代结束时显式地将 handle 变量设置为 null)
  2. 第 13 个元素没有被收集(尽管我从来没有把它存储在任何地方)
  3. if (false) { }(或任何其他循环/条件)对于触发错误至关重要。

是什么导致了这些问题? (我知道在调试中,对象一直保留到定义它们的 block 的末尾。仅此一点仍然不能解释我遇到的任何问题。)

我已将错误提交给 Microsoft,但我对问题的原因更感兴趣 https://connect.microsoft.com/VisualStudio/feedback/details/775082/strangely-triggered-strange-bugs-with-garbage-collection-in-debug-builds

最佳答案

这是 x86 抖动特有的。是的,这看起来像一个错误,抖动将堆栈帧上的临时存储位置标记为有效的对象引用。与 [ebp-74h] 一样,存储 handler[13] 引用的槽和 [ebp-68h] 保持对 handler[19] 的引用。这些临时变量在 x86 代码中很常见,因为 cpu 寄存器的数量很少,并且当优化器被禁用时,抖动花费很少的精力来找到对少数寄存器的良好使用。

您可以在 connect.microsoft.com 上提交反馈报告。然而,他们修复它的可能性非常小,当优化器被禁用时,抖动没有义务使它工作。局部变量的生命周期被延长到方法的末尾,使调试变得容易。对于声明的局部变量以及抖动分配的临时变量为真。当然,这最终无关紧要,您只会将 Release 版本发送给您的客户。当优化的 Release 构建也乱扔垃圾时,请随时提出这个问题,这对 GC 效率有害。

关于c# - 调试版本中带有垃圾收集的奇怪触发的奇怪错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14023721/

相关文章:

c# - catch block 中try-catch-rethrow没有额外处理的原因是什么?

.net - 在什么情况下,我们需要两次调用GC.Collect

debugging - 调试器/异常如何在已编译的程序上工作?

c# - 在这种情况下哪个更好,return 或 ref

c# - 在非 ASP.Net 应用程序中加密连接字符串

c# - 检测 MSMQ 错误

Python pdb(调试器)disp 等效?

mysql - 加载缓慢、1502 个查询和 session 中的大量数据 - 请参阅调试日志

c# - Windows 服务应用程序 app.config

c# - 避免在 LINQ 查询中双重控制搜索