【发布时间】:2020-08-19 16:24:08
【问题描述】:
考虑以下代码:
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
#nullable enable
namespace ConsoleApp1
{
class Program
{
static void Main()
{
var list = makeList();
var weakRef = new WeakReference(list[0]);
list[0] = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(weakRef.IsAlive);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static List<int[]?> makeList()
{
return new List<int[]?> { new int[2] };
}
}
}
- 在 .Net Framework 4.8 上发布或调试版本,
代码打印
False。 - 在 .Net 上发布或调试版本
Core 3.1,该代码打印
True。
是什么导致了这种行为差异? (这导致我们的一些单元测试失败。)
注意:我将列表初始化放入 makeList() 并关闭内联,以尝试使 .Net Core 版本与 .Net Framework 版本相同,但无济于事。
[编辑] 正如 Hans 指出的那样,添加一个循环可以修复它。
以下代码将打印False:
var list = makeList();
var weakRef = new WeakReference(list[0]);
list[0] = null;
for (int i = 0; i < 1; ++i)
GC.Collect();
Console.WriteLine(weakRef.IsAlive);
但这会打印出True:
var list = makeList();
var weakRef = new WeakReference(list[0]);
list[0] = null;
GC.Collect();
GC.Collect();
GC.Collect();
GC.Collect();
// Doesn't seem to matter how many GC.Collect() calls you do.
Console.WriteLine(weakRef.IsAlive);
这必须是某种奇怪的抖动...
【问题讨论】:
-
while (weakRef.IsAlive) { GC.Collect(); GC.WaitForPendingFinalizers(); }。我真的不想猜测为什么它只经过一次循环:) -
@JoeSewell 是的,这似乎是相关的(他们甚至在进行相同类型的单元测试),除了他们还尝试使用为他们修复它的非内联方法(而且它不适用于我)。
-
@HansPassant 这不是最奇怪的事情。我尝试向
GC.Collect()添加 10 个单独的调用,但这并不能解决问题 - 但是一个循环就可以了。嗯。
标签: c# weak-references .net-core-3.1 .net-framework-4.8