我正在编写垃圾收集测试,并偶然发现了在调试模式下发生的一组奇怪的错误。这是一个提炼的 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));
}
在调试模式下,此代码将打印(“未收集的处理程序:13,19”。我对此结果的问题如下:
- 未收集第 19 个元素(即使我在每次循环迭代结束时将句柄变量显式设置为 null)
- 未收集第 13 个元素(即使我从未将其存储在任何地方)
if (false) { }
(或任何其他循环/条件)对于触发错误至关重要。
是什么导致出现问题?(我知道在调试中,对象被保留到定义它们的块的末尾。仅此一点仍然不能解释我遇到的任何问题。)
我已将错误提交给 Microsoft,但我对问题的原因更感兴趣https://connect.microsoft.com/VisualStudio/feedback/details/775082/strangely-triggered-strange-bugs-with-garbage -collection-in-debug-builds