繁体   English   中英

C#中的OutOfMemoryException

[英]OutOfMemoryException in C#

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

几乎可以肯定的问题是,您正在重复分配新数组,并且在内存中它们被分配为连续的块,因此我可以理解它是如何通过它咀嚼的。

如何稍微重新调整一下内容,以便仅创建一次缓冲区然后再使用它,除非您进入所需的块大小小于标准块大小的情况。

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);
    } 
}

我可以建议您尝试使用较小的缓冲区吗?

问题可能是您重复分配了一个大于85000字节的内存块,该内存块进入一个不幸的是从未压缩过的特殊堆(大对象堆)!

有关大对象堆如何工作的详细说明,请参见此处 不幸的是,这可能导致严重的堆碎片,并最终导致内存不足错误,如您所描述的那样(请参阅此处: loh碎片会导致OutOfMemory异常

如果您分配较小的块(小于85,000字节),那么它们将分配在常规堆上,那么GC将能够执行压缩,并且几乎可以肯定,您的问题将消失。 我也强烈建议您按照@Nanhydrin的建议修改您的代码,因为这样可以避免重复分配,并且应该会表现得更好

我不能完全确定“运行足够长的时间”是什么意思,但是该代码分配的数组至少为100 KB(如果文件更大,则可能更大)。 它本身可能不会导致故障,但是在只有32 MB虚拟地址空间的环境中,这是相当大的内存分配。 如果其中许多并行运行,则可以很容易地将其乘以一个相对较高的内存使用率,在这种情况下,您可能会看到OutOfMemoryException

假设context.Response是一个HttpResponse ,看起来您只是试图将文件的内容写入HTTP响应,在这种情况下,您可以使用以下类似方法更有效地做到这一点:

using (var file = new FileStream(fileLoc, FileMode.Open))
{
    CopyStream(file, context.Response.OutputStream);
}

请参见在两个Stream实例之间进行复制的最佳方法-C#中的CopyStream实现,该实现以较小的块为单位逐位复制数据,而不是尝试一次读取整个文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM