There is an article here at CodeProject that explains what is happening and what can be done: A replacement for MemoryStream
A short explanation with my own words:
initially don't know about the size of the required memory. So they will start with a rather small amount of allocated memory. When this memory is used up, they will allocate a new block of typically twice the size, copy the content of the previous block and free that. When needing large amounts of memory this may result in out memory exceptions for three reasons:
- During re-allocation more memory is required (old size * 3)
- The newly allocated block must be contiguous
- With 32-bit applications the limit of 2 GB may be reached
To explain this with your example of 750 MB:
Assuming that the stream actually holds 700 MB, it will try to allocate 1400 MB. This will fail when there is no free contiguous block of this size. Having the existing 700 MB in mind, your stream would actually own more than the half of your installed memory at that time.
If you know the required size in advance, you should use the constructor that accepts the capacity
argument. This avoids multiple re-allocations and allocating unused memory, and you will get an immediate exception if allocation fails.