C#中的OutOfMemoryException

时间:2012-02-21 15:06:07

标签: c# compact-framework

此代码导致某种内存泄漏。我认为它是由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);
    }
}

4 个答案:

答案 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.ResponseHttpResponse,您似乎只是想将文件的内容写入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没有规定什么时候一般会删除项目。