23

I was researching the best way to return 'views' into a very large array and found ArraySegment which perfectly suited my needs. However, I then found Memory<T> which seems to behave the same, with the exception of requiring a span to view the memory.

For the use-case of creating and writing to views into a massive (2GB+) array, does it matter which one is used?

The reasons for the large arrays are they hold bytes of an image.

5
  • 3
    Are you sure having these arrays fully occupying memory is sensible in the first place? Might a MemoryMappedFile be a better starting point? Without knowing your use cases it's going to be difficult for anyone to offer concrete advice. Commented Sep 7, 2018 at 14:43
  • ArraySegment<T> is just a convenience tool to avoid having to add the offset of the segment each time you access the element. Under the hood it still does it, which adds some cost to each call. Memory<T> objects are as efficient as C# arrays. Commented Sep 7, 2018 at 14:46
  • The use case is stitching images together. The resulting image needs to be encoded to .png, hence requiring the whole file to be in memory. Commented Sep 7, 2018 at 14:46
  • 2
    Does this answer your question? How is the new C# Span<T> different from ArraySegment<T>? Commented Aug 21, 2020 at 3:13
  • 1
    ArraySegment is older, hence why it exists. I'd use Memory (or Span, as needed) in all new code. Commented Nov 18, 2020 at 16:02

2 Answers 2

15

Resurrecting this in case someone bumps into this question.

When to use ArraySegment over Memory?

Never, unless you need to call something old that expects an ArraySegment<T>, which I doubt will be the case as it was never that popular.

ArraySegment<T> is just an array, an offset, and a length, which are all exposed directly where you can choose to ignore the offset and length and access the entirety of the array if you want to. There’s also no read-only version of ArraySegment<T>.

Span<T> and Memory<T> can be backed by arrays, similar to ArraySegment<T>, but also by strings and unmanaged memory (in the form of a pointer in Span<T>’s case, and by using a custom MemoryManager<T> in Memory<T>’s case). They provide better encapsulation by not exposing their underlying data source and have read-only versions for immutable access.

Back then, we had to pass the array/offset/count trio to a lot of APIs (APIs that needed a direct reference of an array), but now that Span<T> and Memory<T> exist and are widely supported by most, if not all, .NET APIs that need to interact with continuous blocks of memory, you should have no reason to use an ArraySegment<T>.

See also: Memory- and span-related types - MS Docs

Sign up to request clarification or add additional context in comments.

2 Comments

Another use case for ArraySegment is when calling something that expects IList<T> or IEnumerable<T>, or you want to use LINQ over the data, without having to copy the data in memory. Casting to interfaces or iterating it is not going to be very performant due to boxing, but at least it's possible.
what about the async scenario? You cannot access Memory<T>.Span there, so I suppose this is a legit reason to use the ArraySegment too.
0

Memory is sort of a wrapper around Span - one that doesn't have to be on the stack. And as the link provided by CoolBots pointed out it's an addition to arrays and array segments not really a replacement for them.

The main reason you would want to consider using Span/Memory is for performance and flexibility. Span gives you access to the memory directly instead of copying it back and forth to the array, and it allows you to treat the memory in a flexible way. Below I'll go from using the array as bytes to using it as an array of uint.

I'll skip right to Span but you could use AsMemory instead so you could pass that around easier. But it'd still boil down to getting the Span from the Memory.

Here's an example:

        const int dataSize = 512;
        const int segSize = 256;

        byte[] rawdata = new byte[dataSize];

        var segment = new ArraySegment<byte>(rawdata, segSize, segSize);

        var seg1 = segment.AsSpan();

        var seg1Uint = MemoryMarshal.Cast<byte, uint>(seg1);

        for (int i = 0; i < segSize / sizeof(uint); ++i)
        {
            ref var data = ref seg1Uint[i];

            data = 0x000066;
        }

        foreach (var b in rawdata)
            Console.WriteLine(b);

1 Comment

I would add that the standard API seems to be moving toward favoring Memory and Span over arrays. For example, SocketAsyncEventArgs.MemoryBuffer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.