Watching the .NET Garbage Collector
Here's an interesting use of SciTech's .NET Memory Profiler – watching how objects are handled by the .NET CLR garbage collector.
The sample code create 4 objects – a simple class "Simple", a class that implements IDisposable "Disposable", and a class that also implements a destructor "Destructable".
.NET Memory Profiler can generate a real-time graph of memory allocations. I've instrumented the sample code using SciTech's API to add comments to the graph so you can match the code execution path against the X axis (time). The object instance count is mapped to the Y axis.
See how 2 instances of the "Destructable" class existed around the 10 second mark – then one was released at the first GC, then the 2nd (which has the destructor) is only released after the 2nd GC.
using System; using System.Diagnostics; using SciTech.NetMemProfiler;
namespace MemoryTesting { internal class Program { private static void Main(string[] args) { MemProfiler.FullSnapShot("Start");
CreateSimple();
CreateDisposable();
System.Threading.Thread.Sleep(1000);
CreateDestructableAndDispose();
System.Threading.Thread.Sleep(1000);
CreateDestructable();
System.Threading.Thread.Sleep(1000);
MemProfiler.AddRealTimeComment("GC");
GC.Collect();
System.Threading.Thread.Sleep(2000);
MemProfiler.AddRealTimeComment("WaitForPendingFinalizers");
GC.WaitForPendingFinalizers();
System.Threading.Thread.Sleep(2000);
MemProfiler.AddRealTimeComment("GC");
GC.Collect();
System.Threading.Thread.Sleep(1000);
MemProfiler.AddRealTimeComment("End");
MemProfiler.FullSnapShot();
}
private static void CreateSimple()
{
MemProfiler.AddRealTimeComment("Create Simple");
var a = new Simple();
a.Something += OnEventHandler;
a.Data = "hey";
a.Something -= OnEventHandler;
}
private static void CreateDisposable()
{
MemProfiler.AddRealTimeComment("Create Disposable");
var a = new Disposable();
a.Something += OnEventHandler;
a.Data = "ho";
System.Threading.Thread.Sleep(1000);
a.Something -= OnEventHandler;
a.Dispose();
}
private static void CreateDestructableAndDispose()
{
MemProfiler.AddRealTimeComment("Create Destructable and Dispose");
var a = new Destructable();
a.Something += OnEventHandler;
a.Data = "haha";
System.Threading.Thread.Sleep(1000);
a.Something -= OnEventHandler;
a.Dispose();
}
private static void CreateDestructable()
{
MemProfiler.AddRealTimeComment("Create Destructable");
var a = new Destructable();
a.Something += OnEventHandler;
a.Data = "haha";
System.Threading.Thread.Sleep(1000);
a.Something -= OnEventHandler;
//a.Dispose();
}
private static void OnEventHandler(object sender, EventArgs e)
{
Debug.WriteLine("Something Fired");
}
}
public class Simple
{
private string \_data;
public string Data
{
get { return \_data; }
set
{
\_data = value;
OnSomething(null);
}
}
public event EventHandler Something;
protected virtual void OnSomething(EventArgs e)
{
EventHandler handler = Something;
if (handler != null) handler(this, e);
}
}
public class Disposable : Simple, IDisposable
{
#region IDisposable Members
public void Dispose()
{
System.Threading.Thread.Sleep(1000);
MemProfiler.AddRealTimeComment("Dispose");
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
protected virtual void Dispose(bool disposing)
{
}
}
public class Destructable : Disposable
{
~Destructable()
{
System.Threading.Thread.Sleep(1000);
MemProfiler.AddRealTimeComment("Destructing");
Dispose(false);
}
} }
Categories: .NET