ValueTask & Avoiding Allocations
Use ValueTask to reduce heap allocations in hot paths, understand its constraints, and avoid common misuse pitfalls.
The Allocation Problem with Task
Task<T> is a reference type — every async method allocates a Task on the heap, even if the result is available synchronously (e.g., from a cache). In hot paths this can cause significant GC pressure. ValueTask<T> solves this.
What Is ValueTask?
ValueTask<T> is a struct that can represent either a synchronously available result or a pending async operation. When the result is synchronous, no heap allocation is needed.
// Task<T>: always allocates, even when result is cached
public async Task<string> GetCached_Task() =>
_cache.TryGetValue("key", out var v) ? v : await FetchAsync();
// ValueTask<T>: zero allocation when value is cached
public ValueTask<string> GetCached_ValueTask() =>
_cache.TryGetValue("key", out var v)
? ValueTask.FromResult(v) // no allocation
: new ValueTask<string>(FetchAsync()); // allocation only when neededAll lessons in this course
- IAsyncEnumerable & await foreach
- System.Threading.Channels
- ValueTask & Avoiding Allocations
- ConfigureAwait & Synchronization Context