Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I force release memory occupied by MemoryStream?

I have the following code:

const int bufferSize = 1024 * 1024;
var buffer = new byte[bufferSize];
for (int i = 0; i < 10; i++)
{
    const int writesCount = 400;
    using (var stream = new MemoryStream(writesCount * bufferSize))
    {
        for (int j = 0; j < writesCount; j++)
        {
            stream.Write(buffer, 0, buffer.Length);
        }
        stream.Close();
    }
}

which I run on a 32-bit machine.

The first iteration finishes just fine and then on the next iteration I get a System.OutOfMemoryException exception on the line that news the MemoryStream.

Why isn't the previous MemoryStream memory reclaimed despite using statement? How do I force release of memory used by the MemoryStream?

like image 436
sharptooth Avatar asked Aug 17 '12 08:08

sharptooth


People also ask

How do I dispose of MemoryStream?

MemoryStream does not have any unmanaged resources to dispose, so you don't technically have to dispose of it. The effect of not disposing a MemoryStream is roughly the same thing as dropping a reference to a byte[] -- the GC will clean both up the same way.

How do I reuse MemoryStream?

You can re-use the MemoryStream by Setting the Position to 0 and the Length to 0. By setting the length to 0 you do not clear the existing buffer, it only resets the internal counters.

What is the difference between Stream and MemoryStream?

You would use the FileStream to read/write a file but a MemoryStream to read/write in-memory data, such as a byte array decoded from a string. You would not use a Stream in and of itself, but rather use it for polymorphism, i.e. passing it to methods that can accept any implementation of Stream as an argument.

How does memory stream work?

MemoryStream encapsulates data stored as an unsigned byte array that is initialized upon creation of a MemoryStream object, or the array can be created as empty. The encapsulated data is directly accessible in memory. Memory streams can reduce the need for temporary buffers and files in an application.


2 Answers

I don't think the problem is the garbage collector not doing its job. If the GC is under memory pressure it should run and reclaim the 400 MBs you've just allocated.

This is more likely down to the GC not finding a contigious 400 MB block.

Rather, an “out of memory” error happens because the process is unable to find a large enough section of contiguous unused pages in its virtual address space to do the requested mapping.

You should read Eric Lippert's blog entry "Out Of Memory" Does Not Refer to Physical Memory

You're far better off doing both of the below.

  1. Reusing the memory block you've allocated (why are you creating another with the exact same size)
  2. Allocating much smaller chunks (less than 85KBs)

Prior to Dotnet 4.5, Dotnet constructed two heaps, Small Object Heap (SOH) and Large Object Heap (LOH). See Large Object Hearp Improvements in .NET 4.5 by Brandon Bray. Your MemoryStream is being allocated in LOH, and not compacted (defragmented) for the duration of the process, making it much more likely that multiple calls to allocate this large amount of memory will throw an OutOfMemoryException

The CLR manages two different heaps for allocation, the small object heap (SOH) and the large object heap (LOH). Any allocation greater than or equal to 85,000 bytes goes on the LOH. Copying large objects has a performance penalty, so the LOH is not compacted unlike the SOH. Another defining characteristic is that the LOH is only collected during a generation 2 collection. Together, these have the built-in assumption that large object allocations are infrequent.

like image 103
M Afifi Avatar answered Oct 03 '22 00:10

M Afifi


Looks like you're allocating too much than your system can handle. Your code runs fine on my machine, but if I change it like this :

const int bufferSize = 1024 * 1024 * 2;

I get the same error as you.

But if I change the target processor to x64, then the code runs, which seems logical as you can address lot more memory.

Detailed explanation on this article : http://www.guylangston.net/blog/Article/MaxMemory And some information on this question : Maximum Memory a .NET process can allocate

like image 45
mathieu Avatar answered Oct 03 '22 01:10

mathieu