To detect potential memory-leaks in places where it already happened a lot I have work with tests that are build like the shown below. The main idea is to have an instance, not reference it any longer and let the garbage collector collect it. I would like not to focus on whether this is a good technique or not (in my particular case it did an excellent job) but I would like to focus on the following question:
The code below works perfectly on .NetFramework 4.8 but does not on .Net 5. Why?
[Test]
public void ConceptualMemoryLeakTest()
{
WeakReference weakReference;
{
object myObject = new object();
weakReference = new WeakReference(myObject);
myObject = null;
Assert.Null(myObject);
}
Assert.True(weakReference.IsAlive); // instance not collected by GC
GC.Collect();
GC.WaitForPendingFinalizers();
GC.WaitForFullGCComplete();
GC.Collect();
Assert.False(weakReference.IsAlive); // instance collected by GC
}
You can see the main idea is to work with a WeakReference
and use IsAlive
to determine whether the instance got removed by the GC. How did the rules in the new CLR (the one originating from dotnet core) change? I know that what is done here does not relay on something that is specified. Rather I just exploit the behavior I see with the CLR in NetFramework 4.8.
Do you have an idea how to get something similar again that works also with .Net 5?
Actually with hints provided in the comments and answers I realized that moving the instance to a separate method and prevent in-lining it works:
[MethodImpl(MethodImplOptions.NoInlining)]
private WeakReference CreateWeakReference()
{
object myObject = new object();
return new WeakReference(myObject);
}
[Test]
public void ConceptualMemoryLeakTest()
{
WeakReference weakReference = CreateWeakReference();
Assert.True(weakReference.IsAlive);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.WaitForFullGCComplete();
GC.Collect();
Assert.False(weakReference.IsAlive);
}
This does not require
<TieredCompilation>false</TieredCompilation>