如何解决.Net Framework和.Net Core之间的WeakReference行为不同
考虑以下代码:
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] };
}
}
}
是什么导致这种行为差异? (这导致我们的某些单元测试失败。)
注意:我将列表初始化放入makeList()
中,并关闭了内联,以尝试使.Net Core版本与.Net Framework版本相同,但无济于事。
[EDIT]正如汉斯指出的那样,添加一个循环即可解决该问题。
以下代码 将打印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);
这 got 是某种怪异的Jitter事情...
解决方法
仅因为允许收集 并不意味着它已被义务尽快收集。虽然该语言指出允许GC确定不再读取局部变量,因此不认为它是根,但这并不意味着您可以依赖收集局部变量的内容。在您上次阅读后立即显示。
这不是运行时定义的行为之间的某些更改,这是两个运行时中的未定义行为,因此它们之间的差异是完全可以接受的。
,当我删除列表变量时,我获得了要释放的引用:
using NUnit.Framework;
using System;
using System.Collections.Generic;
namespace NUnitTestProject1
{
public class Tests
{
[TestCase(2,GCCollectionMode.Forced,true)]
public void TestWeakReferenceWithList(int generation,GCCollectionMode forced,bool blocking)
{
static WeakReference CreateWeakReference()
{
return new WeakReference(new List<int[]> { new int[2] });
}
var x = CreateWeakReference();
Assert.IsTrue(x.IsAlive);
GC.Collect(generation,forced,blocking);
Assert.IsFalse(x.IsAlive);
}
}
}
以下测试用例失败:
using NUnit.Framework;
using System;
using System.Collections.Generic;
namespace NUnitTestProject1
{
public class Tests
{
[TestCase(2,bool blocking)
{
static List<int[]> CreateList()
{
return new List<int[]> { new int[2] };
}
WeakReference x;
{
var list = CreateList();
x = new WeakReference(list);
list = null;
}
Assert.IsTrue(x.IsAlive);
GC.Collect(generation,blocking);
Assert.IsFalse(x.IsAlive);
}
}
}
如果查看IL,我们可以确定将null分配给局部变量1:
IL_0003: call class [System.Collections]System.Collections.Generic.List`1<int32[]> NUnitTestProject1.Tests::'<TestWeakReferenceWithList>g__CreateList|0_0'()
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000a: newobj instance void [System.Runtime]System.WeakReference::.ctor(object)
IL_000f: stloc.0
IL_0010: ldnull
IL_0011: stloc.1
IL_0012: nop
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。