C# 调试构建中的垃圾收集奇怪地触发了奇怪的bug

C# 调试构建中的垃圾收集奇怪地触发了奇怪的bug,c#,.net,debugging,garbage-collection,C#,.net,Debugging,Garbage Collection,我正在编写垃圾收集测试,无意中发现了一组在调试模式下出现的奇怪错误。 下面是一个提取的POC代码。 有20个lambda的列表和对它们的弱引用列表。 我访问第13个lambda(调用.ToString()),然后清除列表。 然后强制垃圾收集并分析哪些元素在清理过程中幸存下来 public void TestGC_WTF() { var handlers = new List<Action>(); var weakReferences = new

我正在编写垃圾收集测试,无意中发现了一组在调试模式下出现的奇怪错误。 下面是一个提取的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));
    }
public void TestGC_WTF(){

var handlers=newlist

我不相信
GC.Collect()
必然会收集所有可能的垃圾,只需付出努力。在调试构建中,优化有利于保持引用的活动性,因为您更可能希望使用调试器检查它们。我在这里没有看到任何行为我会称之为错误。

这是特定于x86抖动的。是的,这看起来像是一个错误,jitter正在将堆栈帧上的临时存储位置标记为有效的对象引用。如[ebp-74h],存储处理程序[13]引用的插槽和保留对处理程序[19]引用的[ebp-68h]。由于cpu寄存器数量较少,且当禁用优化器时,jitter在寻找对少数寄存器的良好使用方面花费的精力很少,因此这些临时性在x86代码中很常见


您可以在connect.microsoft.com上提交反馈报告。他们修复该报告的可能性很小,但当禁用优化器时,抖动没有义务使其正常工作。局部变量的生存期延长到方法末尾,以便于调试。对于声明的局部变量以及临时变量,均为True在抖动分配时。当然,这最终无关紧要,你只能将发布版本发送给你的客户。当优化的发布版本也出现问题时,请随时提出这个问题,这对GC的有效性是有害的。

我认为在.NET 4中,GC.Collect()将立即执行完整的GC收集。以前版本的并非如此。NETI知道延长的生存期,但它没有解释我概述的问题,因为所有其他元素都已收集。至于
GC.collect()
,我相信它是相当可靠的。如果它没有收集到什么东西,再多的重试也无济于事。我理解第13个处理程序的原因,但不理解第19个处理程序的原因(该引用不应该在循环结束时设置为null吗?)。让我感兴趣的是
If(false){}
触发器只在代码中添加了
ldc.i4.1
stloc.s
br.s nextLine
。我已经提交了错误报告来查看IL是毫无意义的,抖动产生的机器代码很重要。