Glossary / Memory<T>
Memory
Memory<T> is a heap-storable, mutable view over a contiguous region of T values. Like Span<T>, it supports slicing without copying, but unlike Span it is an ordinary struct that can be stored in objects and carried across asynchronous suspension points.
Usage and conversion
Memory<byte> buffer = new byte[1024];
await FillAsync(buffer);
ReadOnlyMemory<byte> view = buffer[..128];
Memory<T>.Span exposes a temporary Span<T> for synchronous access. ReadOnlyMemory<T> provides a read-only view. Slicing adjusts offset/length and shares backing storage; changes can be observed through other views. The lifetime of the underlying memory must still exceed use. Custom MemoryManager<T> implementations may represent unmanaged or pooled memory and have explicit disposal/lifetime contracts.
Memory is useful for async APIs that need to retain buffers while awaiting. It does not automatically pin memory or make concurrent access safe. Pin only when required for interop, and release pins promptly because they can impede GC compaction. Pooling arrays can reduce allocations but requires returning buffers exactly once and not using them after return.
Engineering guidance
Use Memory for async-capable buffer contracts and Span inside synchronous hot sections. Document ownership, mutability, and whether buffers are pooled. Avoid retaining slices unnecessarily because they keep the backing memory alive. Test cancellation and buffer lifetime through the full async operation.
Interview questions
- Why Memory instead of Span in async APIs? Memory can be stored across await; Span is ref-struct constrained.
- Does slicing copy? No, it shares backing storage.
- Does Memory imply thread safety? No.
- Does Memory pin data? No; pinning is explicit when needed.
- What is the pooled-buffer hazard? Use after return or double return causes corruption/resource bugs.