Search code examples
c#memory-managementmemory-leaksmemorystreamdisposing

How do I force collection of a MemoryStream's underlying buffer?


I'm working with a memory stream and I'm running into some issues with some out of memory exceptions. The method causing the issue is below.

public override T Deserialize<T>(byte[] source)
{
    using (var stream = new MemoryStream(source))
    {
        var result = (T)_formatter.Deserialize(stream);

        return result;
    }
}

And this is a typical call to it:

var bufferSize = binaryArrays.Sum(x => x.Length);
var streamBuffer = new byte[bufferSize];

using (var stream = new MemoryStream(streamBuffer))
{
    foreach (var binaryArray in binaryArrays)
    {
        stream.Write(binaryArray, 0, binaryArray.Length);
    }

    result = serializer.Deserialize<T>(stream.ToArray());
}

I've implemented IDisposable in this method's containing class, and I'm disposing of the stream explicitly (even though it shouldn't be necessary) but I can't reclaim my memory. I understand that it is because the MemoryStream's underlying buffer is still floating around and that my application's virtual memory has been exhausted. So, how to kill the underlying buffer? Are there any techniques I could use here?

Much thanks.

[EDIT]

I fixed the using statement, but the issue is still present. Thanks for the catch.


Solution

  • When you pass a byte array to the MemoryStream constructor, that byte array is the buffer. Perhaps you're still holding onto a reference to that byte array in the calling code?

    The code you've shown won't hold onto the data (assuming it's actually allocating a local variable, rather than assigning to a property) - and disposing of the stream definitely isn't important here, and won't help at all... the data in a MemoryStream is available even after disposal anyway.

    Of course, if the code you've given is really accurate, then I suggest you remove your Serializer and Stream properties/fields. It's very rarely a good idea to have using statements which reuse existing properties/variables rather than declaring new local variables.

    using (Stream stream = new MemoryStream(source))
    {
        return (T) _formatter.Deserializer(stream);
    }