Created
November 13, 2023 09:39
-
-
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#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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