How do I force release memory occupied by MemoryStream?

后端 未结 4 637
北恋
北恋 2021-02-07 12:02

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 = 4         


        
4条回答
  •  一整个雨季
    2021-02-07 12:27

    First of all, Dispose() does not guarantee that memory will be released (it does not mark objects for GC collection, in case of MemoryStream - it releases nothing, as MemoryStream has no unmanaged resources). The only reliable way to free memory used by MemoryStream is to lose all references to it and wait for garbage collection to occur (and if you have OutOfMemoryException - garbage collector already tried but failed to free enough memory). Also, allocating such large objects (anything > 85000 bytes) have some consequences - these objects are going to large object heap (LOH), which can get fragmented (and cannot be compacted). As .NET object must occupy a contiguous sequence of bytes, it can lead to a situation where you have enough memory, but there is no room for large object. Garbage collector won't help in this case.

    It seems like the main problem here is that reference to a stream object is kept on stack, preventing garbage collection of stream object (even forcing garbage collection won't help, as GC considers that object is still alive, you can check this creating a WeakRefrence to it). Refactoring this sample can fix it:

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

    Here is a sample which proves that object can't be garbage collected:

        static void Main(string[] args)
        {
            const int bufferSize = 1024 * 1024 * 2;
            var buffer = new byte[bufferSize];
            WeakReference wref = null;
            for(int i = 0; i < 10; i++)
            {
                if(wref != null)
                {
                    // force garbage collection
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    // check if object is still alive
                    Console.WriteLine(wref.IsAlive); // true
                }
                const int writesCount = 400;
                using(var stream = new MemoryStream(writesCount * bufferSize))
                {
                    for(int j = 0; j < writesCount; j++)
                    {
                        stream.Write(buffer, 0, buffer.Length);
                    }
                    // weak reference won't prevent garbage collection
                    wref = new WeakReference(stream);
                }
            }
        }
    

提交回复
热议问题