---
title: "Span / Memory / ReadOnlySequence in C#"
description: "There are many different memory types used in modern C# programs. The more common ones are `Span<T>` and `Memory<T>`. Occasionally there is also `ReadOnlySequence<T>`. What do these types do?"
updated: 2023-06-08
tags: [".NET", "C#"]
canonical: "https://steven-giesel.com/blogPost/8bb02704-a113-40a1-9414-fe7b8cb3dda5/span-memory-readonlysequence-in-c"
---

# Span / Memory / ReadOnlySequence in C#

There are many different memory types used in modern C# programs. The more common ones are `Span<T>` and `Memory<T>`. Occasionally there is also `ReadOnlySequence<T>`. What do these types do?

## `Span<T>`
Span<T>: Is a fast synchrnous accessor of contiguous memory. It is often used in performance-critical scenarios as there are no new allocations going on when handling with Span. It is a view of a memory slice that is already there. It is a ref struct and therefore has many limitations (like no `async`/`await`, `yield` keyword, ...). `Span<T>` is highly optimized by the compiler and runtime. I will not go into too much detail as I already wrote in detail about `Span<T>`: [*"Create a low allocation and faster StringBuilder - Span in Action"*](https://steven-giesel.com/blogPost/4cada9a7-c462-4133-ad7f-e8b671987896).

## `Memory<T>`
Memory<T>: Is almost the same as Span<T> but doesn't have the limitation of living on the stack. It can be moved to the heap. With that you can use it inside async/await or have it as field on your class.

```csharp
async Task ProcessMemory()
{
    var[] numbers = new int[] { 1, 2, 3, 4, 5 };
    Memory<int> memory = numbers;

    await ProcessAsync(memory);
}

async Task ProcessAsync(Memory<int> memory)
{
    for (var i = 0; i < memory.Length; i++)
    {
        memory.Span[i] *= 2;
        await Task.Delay(100); //simulate async work
    }
}
```

You could not do the same with a `Span<T>` as it is a ref struct and therefore can't be used as field or parameter of an async method.
Sometimes you hear that `Memory<T>` is less optimized than `Span<T>`. But it's inaccurate to say that `Memory<T>` is less optimized than `Span<T>` in .NET. They serve different purposes and have other capabilities. `Span<T>` is a stack-only type that can wrap a segment of any memory, whether it's an array, a portion of a string, or unmanaged memory, whereas `Memory<T>` is a heap-allocated type that can be used more widely, including across async calls.

One could argue that `Span<T>` can be slightly more efficient in some specific scenarios. `Span<T>` allows for higher performance when you want to operate on a small segment of a larger block of data without creating a new array. The reason is that `Span<T>` is a stack-only struct that doesn't create additional heap allocations when slicing, for instance.

In contrast, `Memory<T>` is designed for situations where you might need to slice and dice data but have to work in a context where you cannot use a stack-only type, such as in async methods or when needing to store the data slice for longer periods.

`Memory<T>` and `Span<T>` provide similar capabilities when accessing and slicing data, aiming to minimize unnecessary copying and GC pressure. However, they have different trade-offs in terms of when and where they can be used due to the stack-only nature of `Span<T>`.
So it's not so much a matter of optimization as it is a matter of using the right tool for the right job, depending on the specific needs of your code. It's best to profile and test your code to determine which structure works best for your needs.

## `ReadOnlySpan<T>` and `ReadOnlyMemory<T>`
There is also a readonly version of those types available. The main difference is, as you guessed, the are read only, meaning you can't change the values inside the memory. This is useful if you want to pass a memory slice to a method but don't want the method to change the values. The most prominent example is `ReadOnlySpan<char>` which is used in many string methods.

```csharp
ReadOnlySpan<char> text = "  Hello World  ";
ReadOnlySpan<char> trimmed = text.Trim(); // "Hello World"
```

The code operates purely on the slice of the original string. It doesn't create a new string. This is a very efficient way of working with strings.
I could create the span from the string because there is an implicit conversion from `string` to `ReadOnlySpan<char>`. This is a very common pattern in the .NET framework. Many methods accept `ReadOnlySpan<T>` as parameter and therefore can be used with `string` as well.

## `ReadOnlySequence<T>`
A sequence is a linked list of one or more Memory<T> objects. If you have multiple pieces of memory that you want to tread as "one", this is the data structure of your choice. As consumer of this API it feels like you are "only" handling one memory slice.
```csharp
var array1 = new[] { 1, 2, 3 };
var array2 = new[] { 4, 5, 6 };

var segment1 = new Segment<int>(array1);
var segment2 = new Segment<int>(array2);
segment1.SetNext(segment2);
var sequence = new ReadOnlySequence<int>(segment1, 0, segment2, array2.Length);

foreach(var memory in sequence)
{
    // ...
}

public class Segment<T> : ReadOnlySequenceSegment<T>
{
    public Segment(ReadOnlyMemory<T> memory)
    {
        Memory = memory;
    }

    public void SetNext(Segment<T> next)
    {
        Next = next;
        next.RunningIndex = RunningIndex + Memory.Length;
    }
}
```

The API is not necessary easy to handle as we have to create our own `ReadOnlySequenceSegment<T>` and link them together. But it's very powerful and can be used in many scenarios. For example if you want to read a file from disk and want to process it in chunks. You can read the file in chunks and create a sequence of memory slices. The consumer of the API can then process the file as if it was one big memory slice.

## Overview
Here is a small overview of your mental picture:
![Poster](https://linkdotnetblog.azureedge.net/blog/20230608_SpanMemory/Poster.webp)

## Conclusion
There you got it - different memory types in C#.