此代码导致某种内存泄漏。我认为它是由new byte[]
引起的。
但GC不应该避免这种情况吗?如果程序运行的时间足够长,代码将导致OutOfMemoryException
using (var file = new FileStream(fileLoc, FileMode.Open))
{
int chunkSize = 1024 * 100;
while (file.Position < file.Length)
{
if (file.Length - file.Position < chunkSize)
{
chunkSize = (int)(file.Length - file.Position);
}
byte[] chunk = new byte[chunkSize];
file.Read(chunk, 0, chunkSize);
context.Response.BinaryWrite(chunk);
}
}
答案 0 :(得分:5)
问题几乎可以肯定是你重复分配新的数组,并且在内存中它们被分配为连续的块,所以我可以理解它是如何咀嚼它的。
如何稍微重新调整内容,以便只创建一次缓冲区,然后重复使用它,除非你进入if所需的chunksize小于标准块大小的if。
using (var file = new FileStream(fileLoc, FileMode.Open)) {
int chunkSize = 1024 * 100;
byte[] chunk = new byte[chunkSize];
while (file.Position < file.Length) {
if (file.Length - file.Position < chunkSize) {
chunkSize = (int)(file.Length - file.Position);
chunk = new byte[chunkSize];
}
file.Read(chunk, 0, chunkSize);
context.Response.BinaryWrite(chunk);
}
}
答案 1 :(得分:2)
我建议您尝试使用较小的缓冲区大小吗?
问题可能是你重复分配一个大于85000字节的内存块并且转到一个特殊的堆(大对象堆),遗憾的是它永远不会被压缩!
有关大对象堆如何工作的详细说明,请参阅here。 遗憾的是,这会导致严重的堆碎片,并最终导致内存错误,例如您所描述的错误(请参阅此处:loh fragmentation causes OutOfMemory exception)
如果你分配较小的块(小于85,000字节),那么它们将被分配在常规堆上,然后GC将能够执行压缩,几乎可以肯定,你的问题将会消失。 我还强烈建议您修改@Nanhydrin建议的代码,因为这样可以避免重复分配并且应该稍微好一些
答案 2 :(得分:1)
我不完全确定你的意思是“运行得足够长”但是该代码分配的数组至少为100 KB(如果文件较大则可能更大)。本身这可能不会导致失败,但是在仅32 MB of virtual address space的环境中,这是一个相当大的内存分配。如果其中有许多并行运行,这很容易将其增加到相对较高的内存使用量,在这种情况下,您可能会看到OutOfMemoryException
。
假设context.Response
是HttpResponse
,您似乎只是想将文件的内容写入HTTP响应,在这种情况下,您可以使用类似的方式更有效地执行此操作以下内容:
using (var file = new FileStream(fileLoc, FileMode.Open))
{
CopyStream(file, context.Response.OutputStream);
}
请参阅Best way to copy between two Stream instances - C#了解CopyStream
的实现,它以较小的块逐位复制数据,而不是一次性尝试读取整个文件。
答案 3 :(得分:-1)
GC没有规定什么时候一般会删除项目。