What is the difference between Span<T> and Memory<T> in C# 7.2?
Span<T>
is stack-only in nature while Memory<T>
can exist on the heap.
Span<T>
is a new type we are adding to the platform to represent contiguous regions of arbitrary memory, with performance characteristics on par with T[]. Its APIs are similar to the array, but unlike arrays, it can point to either managed or native memory, or to memory allocated on the stack.
Memory <T>
is a type complementingSpan<T>
. As discussed in its design document,Span<T>
is a stack-only type. The stack-only nature ofSpan<T>
makes it unsuitable for many scenarios that require storing references to buffers (represented withSpan<T>
) on the heap, e.g. for routines doing asynchronous calls.
async Task DoSomethingAsync(Span<byte> buffer) {
buffer[0] = 0;
await Something(); // Oops! The stack unwinds here, but the buffer below
// cannot survive the continuation.
buffer[0] = 1;
}
To address this problem, we will provide a set of complementary types, intended to be used as general purpose exchange types representing, just like
Span <T>
, a range of arbitrary memory, but unlikeSpan <T>
these types will not be stack-only, at the cost of significant performance penalties for reading and writing to the memory.
async Task DoSomethingAsync(Memory<byte> buffer) {
buffer.Span[0] = 0;
await Something(); // The stack unwinds here, but it's OK as Memory<T> is
// just like any other type.
buffer.Span[0] = 1;
}
In the sample above, the
Memory <byte>
is used to represent the buffer. It is a regular type and can be used in methods doing asynchronous calls. Its Span property returnsSpan<byte>
, but the returned value does not get stored on the heap during asynchronous calls, but rather new values are produced from theMemory<T>
value. In a sense,Memory<T>
is a factory ofSpan<T>
.
Reference Document: here
re: this means it can only point to memory allocated on the stack.
Span<T>
can point to any memory: allocated either on the stack or the heap. Stack-only nature of Span<T>
means that the Span<T>
itself (not the memory it points to) must reside only on the stack. This is in contrast to "normal" C# structs, that can reside on the stack or on the heap (either via value-type boxing, or when they are embedded in classes/reference-types). Some of the more obvious practical implications are that you cannot have a Span<T>
field in a class, you cannot box Span<T>
, and you cannot make an array of them.