Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does converting between byte[] and MemoryStream cause overhead?

Tags:

c#

.net

I want to know if there's overhead when converting between byte arrays and Streams (specifically MemoryStreams when using MemoryStream.ToArray() and MemoryStream(byte[]). I assume it's temporary doubling memory usage.

For example, I read as a stream, convert to bytes, and then convert to stream again. But getting rid of that byte conversion will require a bit of a rewrite. I don't want to waste time rewriting it if it doesn't make a difference.

like image 606
Dynamiquel Avatar asked Oct 31 '25 00:10

Dynamiquel


2 Answers

Does MemoryStream(byte[]) cause a memory copy?

No, it's a non-resizable stream, and as such no copy is necessary.

Does MemoryStream.ToArray() cause a memory copy?

Yes, by design it creates a copy of the active buffer. This is to cover the resizable case, where the buffer used by the stream is not the same buffer that was initially provided due to reallocations to increase/decrease its size.

Alternatives to MemoryStream.ToArray() that don't cause memory copy?

Sure, you have MemoryStream.TryGetBuffer (out ArraySegment<byte> buffer), which returns a segment pointing to the internal buffer, whether or not it's resizable. If it's non-resizable, it's a segment into your original array.

You also have MemoryStream.GetBuffer, which returns the entire internal buffer. Note that in the resizable case, this will be a lot larger than the actual used stream space, and you'll have to adjust for that in code.

And lastly, you don't always actually need a byte array, sometimes you just need to write it to another stream (a file, a socket, a compression stream, an Http response, etc). For this, you have MemoryStream.CopyTo[Async], which also doesn't perform any copies.

like image 153
Blindy Avatar answered Nov 01 '25 14:11

Blindy


So, yes.. you are correct in assuming that ToArray duplicates the memory in the stream.

If you want do not want to do this (for efficiency reasons), you could modify the bytes directly in the stream. Take a look at this:

// create some bytes: 0,1,2,3,4,5,6,7...
var originalBytes = Enumerable.Range(0, 256).Select(Convert.ToByte).ToArray();

using(var ms = new MemoryStream(originalBytes)) // ms is referencing bytes array, not duplicating it
{
    // var duplicatedBytes = ms.ToArray(); // copy of originalBytes array

    // If you don't want to duplicate the bytes but want to
    // modify the buffer directly, you could do this:

    var bufRef = ms.GetBuffer();

    for(var i = 0; i < bufRef.Length; ++i)
    {
        bufRef[i] = Convert.ToByte(bufRef[i] ^ 0x55);
    }

    // or this:
    /*
    ms.TryGetBuffer(out var buf);
    for (var i = 0; i < buf.Count; ++i)
    {
        buf[i] = Convert.ToByte(buf[i] ^ 0x55);
    }*/

    // or this:
    /*
    for (var i = 0; i < ms.Length; ++i)
    {
        ms.Position = i;
        var b = ms.ReadByte();

        ms.Position = i;
        ms.WriteByte(Convert.ToByte(b ^ 0x55));
    }*/
}

// originalBytes will now be 85,84,87,86...

ETA:

Edited to add in Blindy's examples. Thanks! -- Totally forgot about GetBuffer and had no idea about TryGetBuffer

like image 23
Andy Avatar answered Nov 01 '25 16:11

Andy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!