How I Debugged an Async Memory Leak with a Custom WithName() Extension
In 2022 I traced a memory leak in a TCP handler system using a custom WithName() extension (I got the concept from Jon Skeet's Stack Overflow answer about task naming, then built my own implementation at the time).
The problem: Handlers weren't canceled and kept running in memory, causing a leak. I suspected the leak was in async handling, I used WithName() to trace async commands:
await ReceiveMessagesAsync().WithName("ReceiveMessagesAsync");
Actual example from application logs (Worker class):
+++++++ GetAwaiter called for task "ReceiveMessagesAsync"
+++++++ OnCompleted called for task "ReceiveMessagesAsync"
....
+++++++ GetResult called for task "ReceiveMessagesAsync"
What WithName() does:
- Wraps tasks with a name (NamedTask
struct). - Logs when GetAwaiter(), OnCompleted(), and GetResult() are called using Console.WriteLine().
- Makes it easy to see which async operations are still running.
- Based on Jon Skeet's Stack Overflow concept about naming async operations for debugging (C# master with 1.5M+ reputation).
Why I used Console.WriteLine() instead of ILogger:
- Simple for temporary/local debugging in April 2022.
- No dependencies needed.
- Quick to test (just run and see output).
- Perfect for showing the concept without extra complexity.
- I don't use this code anymore, no need to spend time on legacy code.
The fix: Once I found the leak, I added an abort method with cancellation token linking:
abortReceivedMessagesTokenSource = new CancellationTokenSource();
combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, abortReceivedMessagesTokenSource.Token);
Why this helps for memory leak debugging:
- Names async commands (easier to trace).
- Shows which operations are still running.
- Makes memory leak debugging much easier.
Thanks to Jon Skeet for the concept that inspired this!
Try it yourself: if you're dealing with async memory leaks in C#, add .WithName() to your async operations to trace them.
Link to the class: DiagnosticTaskExtensions.cs