Skip to content

Instantly share code, notes, and snippets.

sealed class GcFinalizersEventListener : EventListener
{
// from https://docs.microsoft.com/en-us/dotnet/framework/performance/garbage-collection-etw-events
private const int GC_KEYWORD = 0x0000001;
private const int TYPE_KEYWORD = 0x0080000;
private const int GCHEAPANDTYPENAMES_KEYWORD = 0x1000000;
protected override void OnEventSourceCreated(EventSource eventSource)
{
Console.WriteLine($"{eventSource.Guid} | {eventSource.Name}");
void OnEventSourceCreated(EventSource eventSource)
void OnEventWritten(EventWrittenEventArgs eventData)
protected override void OnEventSourceCreated(EventSource eventSource)
{
Console.WriteLine($"{eventSource.Guid} | {eventSource.Name}");
}
// from https://blogs.msdn.microsoft.com/dotnet/2018/12/04/announcing-net-core-2-2/
// Called whenever an event is written.
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
// Write the contents of the event to the console.
Console.WriteLine($"ThreadID = {eventData.OSThreadId} ID = {eventData.EventId} Name = {eventData.EventName}");
for (int i = 0; i < eventData.Payload.Count; i++)
{
string payloadString = eventData.Payload[i] != null ? eventData.Payload[i].ToString() : string.Empty;
Console.WriteLine($" Name = \"{eventData.PayloadNames[i]}\" Value = \"{payloadString}\"");
var source = userSession.Source;
source.NeedLoadedDotNetRuntimes();
source.AddCallbackOnProcessStart((TraceProcess proc) =>
{
proc.AddCallbackOnDotNetRuntimeLoad((TraceLoadedDotNetRuntime runtime) =>
{
runtime.GCStart += (TraceProcess p, TraceGC gc) =>
{
// a GC is starting
};
public class PhantomObjectFinalizer : PhantomReference<LargeObject>
{
private int _handle;
public PhantomObjectFinalizer(ReferenceQueue<LargeObject> queue, LargeObject value)
: base(queue, value)
{
_handle = value.Handle;
}
public class PhantomObjectFinalizer<T, S> : PhantomReference<T> where T : class
{
public S State;
public PhantomObjectFinalizer(ReferenceQueue<T> queue, T value, S state)
: base(queue, value)
{
State = state;
}
}
public class LargeObject : IDisposable
{
...
class NativeState
{
public bool _disposed;
public IntPtr _handle1;
public IntPtr _handle2;
public class LargeObject : IDisposable
{
private static readonly Cleaner<LargeObject, NativeState> _cleaner;
static LargeObject()
{
_cleaner = new Cleaner<LargeObject, NativeState>(Cleanup, OnError);
}
private NativeState _state;
/// T is the type to finalize
/// S contains the native state of T to be cleaned up
/// This separation enforces the pattern where the "native" part stored by a managed type is kept in a State
/// The state could even be used as is in T (kind of a SafeHandle holding several native resources)
public class Cleaner<T, S>
where T : class
{
...
private readonly ReferenceQueue<T> _queue;