
The State Machine Your async Method Compiles Into
An async method that never suspends allocates nothing. The same method, suspended once, allocates 160 bytes. The cost is not the keyword — it is the suspension.
Async in production · Part 1
Long-form · since 2026
Long-form technical writing about the CLR, the JIT, the garbage collector and the frameworks built on top.

An async method that never suspends allocates nothing. The same method, suspended once, allocates 160 bytes. The cost is not the keyword — it is the suspension.
Async in production · Part 1
A lambda that captures an int allocated 24 bytes on .NET 10.0.12; the same lambda reading a constant allocated none. The delegate was optional, the display class was not.

On .NET 10.0.12 a shared lock matched a per-thread lock at one thread and cost more from two up, where Monitor.LockContentionCount left zero.

On EF Core 10.0.12, AsEnumerable() before Where().Count() sent a full-table SELECT instead of COUNT(*) and allocated 1056.36 KB against 49.53 KB at 1,000 rows.

In a dotnet-dump of a contested lock, clrstack -all marked no thread as the owner. syncblk named it, and a suspended await appeared only in dumpasync.

Environment.ProcessorCount is the CPU quota rounded up, never below 1. The thread pool minimum follows it, and Server GC switches itself off at 1.

Assigning a struct to an interface allocated 0 bytes. Passing it across a call boundary allocated 24. A constrained generic allocated none, until its body asked for an object.

Multi-part investigations, in reading order.