C# MemoryPool — Complete Guide
In this tutorial, you'll learn about C# MemoryPool. We cover key concepts, practical examples, and best practices.
Your application allocates and discards byte buffers for network I/O, serialization, or file processing. Each allocation puts pressure on the GC, causing pauses. MemoryPool<T> provides a pool of reusable Memory<T> buffers, reducing allocations and GC pressure.
Wrong
public async Task ProcessStreamAsync(Stream stream)
{
byte[] buffer = new byte[4096]; // New allocation every call
int bytesRead = await stream.ReadAsync(buffer);
// Buffer is garbage-collected when method exits
}
Output: Works. But byte[] is allocated per call, creating GC pressure in high-throughput scenarios.
Right
public async Task ProcessStreamAsync(Stream stream)
{
using IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(4096);
Memory<byte> buffer = owner.Memory;
int bytesRead = await stream.ReadAsync(buffer);
// Buffer is returned to the pool when disposed
}
Output: Same functionality. The buffer is rented from a shared pool and returned when disposed. No allocation after warmup.
MemoryPool<T>.Shared is a singleton that maintains a pool of arrays. The default pool uses ArrayPool<T> internally.
using IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(4096);
Span<byte> span = owner.Memory.Span; // Access as span
Prevention
- Use
MemoryPool<T>for short-lived buffers in high-throughput paths. - Use
IMemoryOwner<T>withusingto ensure buffers are returned to the pool. - Use
ArrayPool<T>when you needT[]directly instead ofMemory<T>. - Use
MemoryPool<T>.Sharedfor the default pooled buffer. - Rent the approximate size you need — the pool may return a larger buffer.
- Return buffers promptly — holding them starves the pool.
- Do not use pooled buffers as long-lived caches — they are meant for short-term use.
Common Mistakes with memory pool
- Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists - Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
MemoryPool<T> is used in Durga Antivirus Pro's scanning pipeline for zero-allocation buffer management. For more C# performance, visit DodaTech.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro