Consider the following code:
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] };
}
}
}
- With either a release or a debug build on .Net Framework 4.8, that
code prints
False
. - With either a release or a debug build on .Net
Core 3.1, that code prints
True
.
What is causing this difference in behaviour? (It's causing some of our unit tests to fail.)
Note: I put the list initialisation into makeList()
and turned off inlining in an attempt to make the .Net Core version work the same as the .Net Framework version, but to no avail.
[EDIT] As Hans pointed out, adding a loop fixes it.
The following code will print 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);
But this will print 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);
This has got to be some kind of weird Jitter thing...