64

The .NET MemoryStream does not appear to have a .Reset or .Clear method.

I was thinking of using the following code to accomplish this:

ms.Seek(0, IO.SeekOrigin.Begin)
ms.SetLength(0)

What is the proper way to clear or reset an existing .NET MemoryStream?

  • 9
    **Just to clear this question.** I think he's wondering which method prevents memory being allocated. In theory, `SetLength(0)` should retain `Capacity` while assigning a `new MemoryStream()` should free this memory and allocate new. Depending on use, one might wish to preserve memory and just reset the stream's `Length` and `Position`. *(anyway, this is how a memory conscious C++ programmer would think)* – CodeAngry Jul 15 '14 at 11:59
  • 1
    **And the OP's code is legit.** `.Capacity` remains after those instructions so it's the best way to avoid a free/alloc when not necessary. – CodeAngry Jul 15 '14 at 12:06

5 Answers5

104

Why do you need resetting memory stream? You always can create a new one. Or you can use:

memoryStream.SetLength(0);
Andrew Bezzub
  • 15,744
  • 7
  • 51
  • 73
  • Came across this late but Andrew is correct. Leaving this here since I had to check. MSDN: If the specified value is larger than the current capacity and the stream is resizable, the capacity is increased ... stream between the old and the new length are initialized to zeros. – Rig Oct 12 '14 at 16:05
  • 1
    Thats not working when you reread data into the stream. Position and length will be 0! – Martin.Martinsson Oct 27 '16 at 13:46
  • 6
    Creating a new memorystream causes an allocation. Some programs are performance-sensitive and every allocation counts. – Nic Foster Apr 11 '19 at 19:24
  • @NicFoster What's the purpose of `memoryStream.SetLength(0)`? Will I be able to write to the stream again? – silkfire Jul 23 '21 at 21:17
  • @silkfire, it clears the memory stream, so you can reuse it, as opposed to creating a new one which will allocate memory (slower). – Nic Foster Jul 29 '21 at 22:44
34

Since a MemoryStream is essentially a byte array with an index (and some other supporting members) clearing the byte array and resetting the index can be considered resetting and clearing the MemoryStream. If the initial state of a MemoryStream is a zeroed array with a position of zero then an example of a MemoryStream reset may be:

public static void Clear(this MemoryStream source)
{
  byte[] buffer = source.GetBuffer();
  Array.Clear(buffer, 0, buffer.Length);
  source.Position = 0;
  source.SetLength(0);
}

It is incorrect to say that MemoryStream.SetLength alone resets or clears the MemoryStream since SetLength only clears the internal buffer array if the length exceeds the current buffer's length.

Reinitializing a MemoryStream is a valid approach but less efficient. One benefit of reinitializing the MemoryStream would be to guarantee that the stream was never closed. Once the MemoryStream is closed it can no longer be changed. If you can ensure that the MemoryStream instance isn't closed then clearing the buffer may be the way to go.

Rana Ian
  • 724
  • 7
  • 6
  • 1
    .Reset() shouldn't be zeroing the data right? Only .Clear() should do that... PS - Any way to read the data length after the stream is closed? (ie: without private reflection hopefully) –  Apr 28 '14 at 20:35
  • Just want to underscore an important point here: if you use the buffer directly, you *are* at risk of reading 'old' data if you don't zero the buffer when you reset the position to zero. However, if you stick to using the Read() methods, this *won't* happen - bytes past the 'end' of the stream are not copied from one buffer to the other. – piers7 Feb 19 '16 at 02:24
  • 2
    Always getting an exception for a valid non-empty stream when calling `source.GetBuffer()`: _MemoryStream's internal buffer cannot be accessed_. **upd**: here explained why: http://stackoverflow.com/a/1646219/44217 – Mar Apr 29 '16 at 12:30
  • setting the length to 0 also sets the position to 0, so setting the position is redundant – Dmitrii Dovgopolyi Mar 29 '19 at 12:25
  • This is the best answer from a security perspective. For example: when using a MemoryStream with a CryptoStream, you can ensure that the memory is zeroed immediately when you are done with it instead of waiting for the garbage collector to get around to deallocating the objects (if that even zeros the bytes). – Thoryn Hawley Apr 20 '20 at 21:50
1

I used DotMemory to Profile @Rana_Ian solution, and I called GC to enforce full collection. I found that large Streams will stuck in LOH! And after adding one extra line

public static void Clear(MemoryStream ms)
{
    var buffer = ms.GetBuffer();
    Array.Clear(buffer, 0, buffer.Length);
    ms.Position = 0;
    ms.SetLength(0);
    ms.Capacity = 0; // <<< this one ******
}

I clicked on F12 to see Capacity Implementation, And I found this (I simplified generated code a little bit - I'm using Resharper):

public virtual int Capacity
{
  get
  { .... // some code }
  set
  {
    if ((long) value < this.Length) { // throw some ex }
    if (!this._isOpen) { // some another code }
    if (!this._expandable && value != this.Capacity) { //MemoryStreamNotExpandable }
    if (!this._expandable || value == this._capacity) return;
    if (value > 0)
    {
      byte[] numArray = new byte[value];
      if (this._length > 0)
        Buffer.InternalBlockCopy((Array) this._buffer, 0, (Array) numArray, 0, this._length);
      this._buffer = numArray;
    }
    else
      this._buffer = (byte[]) null; /// <<<< that's it! I need this one
    this._capacity = value;
  }
}

So It's clearing the Buffer, I'm not sure if this is correct or not!

bunjeeb
  • 1,096
  • 1
  • 17
  • 32
-1

you can create your memorystream like this:

public class ResettableMemoryStream : MemoryStream
{
    public void Reset()
{
    Seek(0, SeekOrigin.Begin);
}
}  

and after your operation in your code call:

 buffer.Reset();
desertnaut
  • 57,590
  • 26
  • 140
  • 166
-4

The memorystream does not have a reset/clear method because it would be redundant. By setting it to zero length you clear it.

Of course you could always do:

memoryStream = new MemoryStream(memoryStream.Capacity());

This would yield you a memorystream of the same size that is initialized.

If you really want to manually clear the stream I suspect you would have to resort to looping through the elements.

omglolbah
  • 293
  • 1
  • 6
  • 27
    -1 Why a new Stream of same capacity when you could `.SetLength(0);` and retain capacity? Memory abuse in action. – CodeAngry Jul 15 '14 at 12:04
  • 1
    also doesnt work if you use the stream with a using statement. Would prefer .SetLenght(0) too – Cadburry Apr 13 '15 at 13:10
  • 1
    That is why my answer points out that setting it to zero length clears it.. then elaborates on how to get a stream of the same length that is initialized by the constructor. – omglolbah Apr 21 '16 at 02:01