Skip to content

Instantly share code, notes, and snippets.

@Keboo
Created May 5, 2020
Embed
What would you like to do?
Some GC thoughts on making sure objects are cleaned up.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace GC
{
/*
In dotnet core, finalizer does not appear to be called on shutdown
*/
class Program
{
static void Main(string[] args)
{
DoThing();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
DoThing();
}
static void DoThing()
{
var thing1 = new Thing();
}
}
public class Thing : Cleanup
{
protected override void DisposeManaged()
{
WriteLine();
}
}
public class Thing2 : ICleanup
{
~Thing2()
{
ICleanup.Dispose2(this, false);
System.GC.SuppressFinalize(this);
}
public Thing2()
{
this.RegisterForCleanup();
}
bool ICleanup.IsDisposed { get; set; }
void ICleanup.DisposeManaged()
{
}
void ICleanup.DisposeUnmanged()
{
}
}
public interface ICleanup : IDisposable
{
void IDisposable.Dispose()
{
Dispose(true);
}
bool IsDisposed { get; protected set; }
protected static void Dispose2(ICleanup thing, bool disposing)
{
thing.Dispose(disposing);
}
protected void Dispose(bool disposing)
{
if (IsDisposed) return;
if (disposing)
{
DisposeManaged();
}
DisposeUnmanged();
IsDisposed = true;
}
protected void DisposeManaged();
protected void DisposeUnmanged();
}
public abstract class Cleanup : ICleanup
{
private static int _instanceCount;
private int _id = Interlocked.Increment(ref _instanceCount);
~Cleanup()
{
WriteLine();
ICleanup.Dispose2(this, false);
System.GC.SuppressFinalize(this);
}
bool ICleanup.IsDisposed { get; set; }
protected Cleanup()
{
WriteLine();
this.RegisterForCleanup();
}
protected abstract void DisposeManaged();
protected virtual void DisposeUnmanged() { }
protected void WriteLine(string message = null, [CallerMemberName] string name = null)
=> Console.WriteLine($"{name} {_id} {message ?? "was called"}");
void ICleanup.DisposeManaged() => DisposeManaged();
void ICleanup.DisposeUnmanged() => DisposeUnmanged();
}
public static class Disposable
{
public static void RegisterForCleanup(this IDisposable disposable)
{
var myself = new WeakReference<IDisposable>(disposable);
AppDomain.CurrentDomain.ProcessExit
+= (_, __) =>
{
if (myself.TryGetTarget(out IDisposable thing2))
{
thing2.Dispose();
}
else
{
Console.WriteLine("WeakRef dead");
}
};
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment