C# 如何强制释放MemoryStream占用的内存?
我有以下代码:C# 如何强制释放MemoryStream占用的内存?,c#,.net,memory-management,garbage-collection,idisposable,C#,.net,Memory Management,Garbage Collection,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 <
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();
}
}
const int bufferSize=1024*1024;
var buffer=新字节[bufferSize];
对于(int i=0;i<10;i++)
{
常量int writesCount=400;
使用(var流=新的MemoryStream(writeCount*bufferSize))
{
对于(int j=0;j
我在32位机器上运行
第一次迭代完成得很好,然后在下一次迭代中,我在new
sMemoryStream
行上得到一个System.OutOfMemoryException
异常
为什么以前的
MemoryStream
内存没有被回收,尽管使用了
语句?如何强制释放MemoryStream使用的内存?当您确定有必要清理未引用的对象时,尝试强制垃圾收集
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
另一种选择是将流
与外部存储一起使用:文件流
,例如
但是,在一般情况下,最好使用一个足够小的缓冲区(数组,分配一次)并将其用于读/写调用。避免在.NET中有许多大型对象(请参阅)
更新
假设writescont
是常量,那么为什么不分配一个缓冲区并重用它呢
const int bufferSize = 1024 * 1024;
const int writesCount = 400;
byte[] streamBuffer = new byte[writesCount * bufferSize];
byte[] buffer = new byte[bufferSize];
for (int i = 0; i < 10; i++)
{
using (var stream = new MemoryStream(streamBuffer))
{
for (int j = 0; j < writesCount; j++)
{
stream.Write(buffer, 0, buffer.Length);
}
}
}
const int bufferSize=1024*1024;
常量int writesCount=400;
byte[]streamBuffer=新字节[WriteCount*bufferSize];
字节[]缓冲区=新字节[bufferSize];
对于(int i=0;i<10;i++)
{
使用(var流=新内存流(streamBuffer))
{
对于(int j=0;j
看起来您分配的资源超出了系统的处理能力。您的代码在我的机器上运行良好,但如果我这样更改它:
const int bufferSize = 1024 * 1024 * 2;
我和你犯了同样的错误
但是如果我将目标处理器更改为x64,那么代码将运行,这似乎是合乎逻辑的,因为您可以处理更多的内存
关于本文的详细说明:
关于这个问题的一些信息:我认为问题不在于垃圾收集器没有做好它的工作。如果GC在内存压力下,它应该运行并回收刚才分配的400 MB 这更可能是由于GC没有找到连续的400 MB块 相反,发生“内存不足”错误是因为进程无法运行 在其中查找足够大的连续未使用页部分 用于执行请求映射的虚拟地址空间 你应该读埃里克·利珀特的博客 你最好同时做下面的两件事
MemoryStream
正在LOH中分配,并且在整个过程中没有被压缩(碎片整理),这使得分配如此大量内存的多个调用更有可能引发OutOfMemoryException
CLR管理两个不同的堆进行分配,即小对象
堆(SOH)和大对象堆(LOH)。有更大的分配吗
LOH上的字节数大于或等于85000字节。复制大型对象
具有性能惩罚,因此LOH不像SOH那样紧凑。
另一个定义特征是LOH仅被收集
在第2代收集期间。这些都有内置的功能
假设大型对象分配很少
首先,
Dispose()
不保证释放内存(在MemoryStream
的情况下,它不为GC收集标记对象-它不释放任何内容,因为MemoryStream
没有非托管资源)。释放MemoryStream
使用的内存的唯一可靠方法是丢失对它的所有引用,并等待垃圾回收发生(如果您有OutOfMemoryException
,垃圾回收器已尝试但未能释放足够的内存)。此外,分配这样大的对象(任何大于85000字节的对象)都会产生一些后果——这些对象将被放入大对象堆(LOH),这可能会导致碎片化(并且无法压缩)。由于.NET对象必须占用一个连续的字节序列,因此可能会导致这样的情况:您有足够的内存,但没有空间容纳大型对象。在这种情况下,垃圾收集器没有帮助
这里的主要问题似乎是对流
对象的引用保留在堆栈上,从而阻止流
对象的垃圾收集(即使强制垃圾收集也没有帮助,因为GC认为该对象仍然是活动的,您可以检查这一点,为其创建一个WeakRefrence
)。重构此示例可以解决此问题:
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);
}
}
}
static void Main(字符串[]args)
{
const int bufferSize=1024*1024*2;
var buffer=新字节[bufferSize];
对于(int i=0;i<10;i++)
{
常量int writesCount=400;
写入(缓冲区、写计数、缓冲区大小);
}
}
静态无效写入(字节[]缓冲区、整数写入计数、整数缓冲区大小)
{
使用(var流=新的MemoryStream(writeCount*bufferSize))
{
对于(int j=0;j
下面是一个示例,它证明了对象不能被垃圾收集:
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);
}
}
}
static void Main(字符串[]args)
{
const int bufferSize=1024*1024*2;