首先,
Dispose()
并不能保证内存会被释放(它不会标记对象以进行GC收集,在
MemoryStream
的情况下-它什么也不释放,因为
MemoryStream
没有非托管资源)。释放
MemoryStream
使用的内存的唯一可靠方法是失去对它的所有引用并等待垃圾回收发生(如果您有
OutOfMemoryException
-垃圾回收器已经尝试但未能释放足够的内存)。此外,分配这样大的对象(任何> 85000字节)都会产生一些后果-这些对象将进入大对象堆(LOH),该堆可能会变得碎片化(并且无法压缩)。由于.NET对象必须占用连续的字节序列,因此可能会导致这样一种情况:您拥有足够的内存,但没有足够的空间来存放大对象。在这种情况下,垃圾回收器无法提供帮助。
似乎这里的主要问题是在堆栈上保留了对
stream
对象的引用,从而防止了
stream
对象的垃圾回收(即使强制进行垃圾回收也无济于事,因为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(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)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine(wref.IsAlive);
}
const int writesCount = 400;
using(var stream = new MemoryStream(writesCount * bufferSize))
{
for(int j = 0; j < writesCount; j++)
{
stream.Write(buffer, 0, buffer.Length);
}
wref = new WeakReference(stream);
}
}
}
stream.Close()
。using
语句将调用stream.Dispose()
,而后者已经调用了Close()
。点击此处以获取更多信息 - Manuzor