Blog
Home

Debug Skills, Part 1

6 July 2026 · 70 views

Part 1 of 3 in Debugging Skills

Debug Skills, Part 2 →

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

Co-authored with Claude.

If this was useful, you can buy me a coffee.

New articles: follow via RSS.

Comments

← All articlesView as Markdown