如何强制MemoryStream占用释放内存?

sha*_*oth 14 .net c# garbage-collection memory-management idisposable

我有以下代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我在32位机器上运行.

第一次迭代完成就好了,然后下一个迭代我收到了System.OutOfMemoryException关于该行例外newS中MemoryStream.

MemoryStream尽管有using声明,为什么以前的记忆没有被收回?我如何强制释放所使用的内存MemoryStream

M A*_*ifi 13

我不认为问题是垃圾收集器没有完成它的工作.如果GC处于内存压力下,它应该运行并回收刚刚分配的400 MB.

这更有可能归结为GC没有找到一个有名的400 MB块.

相反,发生"内存不足"错误是因为进程无法在其虚拟地址空间中找到足够大的连续未使用页面部分来执行请求的映射.

您应该阅读Eric Lippert的博客文章"Out of Memory"并不是指物理内存

做下面两种情况你会好得多.

  1. 重用您已分配的内存块(为什么要创建具有完全相同大小的内存块)
  2. 分配更小的块(少于85KB)

在Dotnet 4.5之前,Dotnet构建了两个堆,小对象堆(SOH)大对象堆(LOH).请参阅Brandon Bray 在.NET 4.5中大对象听力改进.您MemoryStream正在LOH中进行分配,并且在进程持续时间内未进行压缩(碎片整理),因此分配大量内存的多次调用将更有可能抛出OutOfMemoryException

CLR管理两个不同的分配堆,小对象堆(SOH)和大对象堆(LOH).任何大于或等于85,000字节的分配都在LOH上.复制大型对象会降低性能,因此与SOH不同,LOH不会被压缩.另一个定义特征是LOH仅在第2代收集期间收集.它们共同具有内置的假设,即大对象分配很少.