Skip to content

Instantly share code, notes, and snippets.

@a-usr
Created November 13, 2023 09:39
Show Gist options
  • Save a-usr/7f33a47ae37ca216f0b59d59e9783a19 to your computer and use it in GitHub Desktop.
Save a-usr/7f33a47ae37ca216f0b59d59e9783a19 to your computer and use it in GitHub Desktop.
A small demonstration of when an object is eligible for Garbage Collection in C#
using Terminal.Gui;
internal class Program
{
static View? StaticReferencetoTestObj2;
public View? InstanceReferenceToTestObj3;
private static void Main(string[] args)
{
// create new instance of program class
Program This = new Program();
// start the test and retrieve the list of references
var refs = This.Test();
// check wether some new objects can be disposed
TryCollectAll(refs);
printCheckAlive(refs);
// free Instance Reference, collect and print
Console.WriteLine("Freeing instance reference to TestObj3");
This.InstanceReferenceToTestObj3 = null;
TryCollectAll(refs);
printCheckAlive(refs);
// free static reference, collect and print
Console.WriteLine("Freeing static reference to TestObj2");
StaticReferencetoTestObj2 = null;
TryCollectAll(refs);
printCheckAlive(refs);
//end
}
private List<WeakReference> Test()
{
List<WeakReference> refs = new List<WeakReference>();
//create new disposable objects and Weakreferences pointing to them.
// you can use any disposable class type instead of Terminal.Gui`s View
View? TestObj1 = new();
refs.Add(new WeakReference(TestObj1));
View? TestObj2 = new();
refs.Add(new WeakReference(TestObj2));
View? TestObj3 = new();
refs.Add(new WeakReference(TestObj3));
View? TestObj4 = new();
refs.Add(new WeakReference(TestObj4));
View? TestObj5 = new();
refs.Add(new WeakReference(TestObj5));
// retrieve TestObj6 from a function instead of directly from a call to new();
View? TestObj6 = createTestObj6();
refs.Add(new WeakReference(TestObj6));
// create additional references to object 2, 3 and 4
StaticReferencetoTestObj2 = TestObj2;
InstanceReferenceToTestObj3 = TestObj3;
View? LocalReferenceToTestObj4 = TestObj4;
// check wether the objects are alive
Console.WriteLine("Initial Check");
printCheckAlive(refs);
// dispose objects
// this is done implicitly to make extending of the test easier
Console.WriteLine("Disposing all objects");
foreach(WeakReference wr in refs)
{
((IDisposable)wr.Target).Dispose();
}
// Try to collect all objects and check again
TryCollectAll(refs);
printCheckAlive(refs);
// remove references from the TestObjI variables (Except TestObj5) and
// make sure all collectible objects are collected.
Console.WriteLine("Setting TestObjI references to null (except for TestObj5)");
TestObj1 = null;
TestObj2 = null;
TestObj3 = null;
TestObj4 = null;
//TestObj5 = null
TestObj6 = null;
TryCollectAll(refs);
// check again
printCheckAlive(refs);
// check wether they are actually null
Console.WriteLine("Are they null though?");
Console.WriteLine("Is the TestObj1 variable null? " + (TestObj1 is null));
Console.WriteLine("Is the TestObj2 variable null? " + (TestObj2 is null));
Console.WriteLine("Is the TestObj3 variable null? " + (TestObj3 is null));
Console.WriteLine("Is the TestObj4 variable null? " + (TestObj4 is null));
Console.WriteLine("Is the TestObj5 variable null? " + (TestObj5 is null));
Console.WriteLine("Is the TestObj6 variable null? " + (TestObj6 is null));
Console.WriteLine();
Console.Out.Flush();
// return so that all leftover locals are freed and the GC evaluates wether their objects are eligible for collection
Console.WriteLine("Returning from function and freeing locals");
return refs;
}
static void printCheckAlive(List<WeakReference> refs)
{
for (int i = 0; i < refs.Count; i++)
{
Console.WriteLine("Was test object " + (i + 1) + " Garbage-Collected? " + !(refs[i].IsAlive));
}
Console.WriteLine();
}
static void TryCollectAll(List<WeakReference> refs)
{
foreach (WeakReference r in refs)
{
// Code snippet from
// https://learn.microsoft.com/en-us/dotnet/standard/assembly/unloadability#use-a-custom-collectible-assemblyloadcontext
// (at the very end of the section)
for (int i = 0; r.IsAlive && (i < 10); i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
static View createTestObj6()
{
return new View();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment