在尝试 WeakHandles 时,我在 .NET 6 上发现了这个特性。
static void Main(string[] args) {
var foo = new int[3];
var fooWeakHandle = GCHandle.Alloc(foo, GCHandleType.Weak);
GC.Collect();
Console.WriteLine(fooWeakHandle.Target);
}
.NET 6 的结果(在发布模式下编译以避免急切的根收集)令人惊讶
System.Int32[]
在 .NET Framework 4.7.2 下,Release 中为 null/nothing,而 Debug 中为 System.Int32[]。 我使用 LinqPad (optimize+-) for Framework 和 .NET(Core) 得到了相同的结果。
为什么仅被 WeakHandle 引用的数组没有被垃圾回收?
在.net框架中
foo
在最后一次使用后有资格收集。 GCHandle.Alloc(foo, GCHandleType.Weak)
是最后一次使用,所以可以在GC.Collect()
领取。
这在进行本机互操作时可能会导致问题,因为对象可能拥有本机资源,而 GC 无法知道这些资源是否被本机代码使用,这可能会导致过早处置资源。如果您没有意识到 GC 的这个怪癖,这可能会是相当意外的,但它可以通过 GC.KeepAlive 来修复。
此行为显然已在更高版本的 .net 版本中发生了变化。我不知道确切的原因,但我的猜测是错误的风险超过了收集性能的微小改进。
因此,这实际上并不是弱引用的变化,而是对象何时被视为可收集的变化。