填充MemoryStream时OutOfMemoryException:在16GB系统上分配256MB

时间:2013-03-24 04:07:51

标签: c# asp.net memory out-of-memory

我在64位Windows 7计算机上运行以下方法在我的开发IIS服务器(来自VS2010 IDE)上运行了16GB的内存:

public static MemoryStream copyStreamIntoMemoryStream(Stream stream)
{
    long uiLen = stream.Length;
    byte[] buff = new byte[0x8000];

    int nSz;
    MemoryStream ms = new MemoryStream();
    try
    {
        while ((nSz = stream.Read(buff, 0, buff.Length)) != 0)
        {
            ms.Write(buff, 0, nSz);
        }
    }
    finally
    {
        Debug.WriteLine("Alloc size=" + ms.Length);
    }

    return ms;
}

我在这一行得到System.OutOfMemoryException

ms.Write(buff, 0, nSz);

分配268435456个字节时抛出:

  

Alloc size = 268435456

,即0x10000000或256 MB。所以我想知道是否需要设置一些全局设置才能使其正常工作?

以下是项目配置设置的屏幕截图: enter image description here

2 个答案:

答案 0 :(得分:27)

简短回答 - 开发服务器是32位进程。

长期回答“为什么只有256Mb?”

首先,让我们了解它是如何运作的。

MemoryStream有内部byte []缓冲区来保存所有数据。它无法预测此缓冲区的确切大小,因此它只是用一些初始值初始化它。

位置和长度属性不反映实际的缓冲区大小 - 它们是反映写入的字节数的逻辑值,并且很容易小于实际的物理缓冲区大小。

当此内部缓冲区无法容纳所有数据时,它应该“重新调整大小”,但在现实生活中,它意味着创建新缓冲区的大小是之前的两倍,然后复制数据从旧缓冲区到新缓冲区。

因此,如果缓冲区的长度为256Mb,并且需要写入新数据,这意味着.Net需要找到另一个512Mb的数据块 - 其余部分都已就绪,所以堆应该在当您收到OutOfMemory时,在内存分配时至少768Mb。

另请注意,默认情况下.Net中没有单个对象(包括数组)的大小超过2Gb。

好的,所以这里是模拟正在发生的事情的样本:

        byte[] buf = new byte[32768 - 10];

        for (; ; )
        {
            long newSize = (long)buf.Length * 2;
            Console.WriteLine(newSize);

            if (newSize > int.MaxValue)
            {
                Console.WriteLine("Now we reach the max 2Gb per single object, stopping");
                break;
            }

            var newbuf = new byte[newSize];
            Array.Copy(buf, newbuf, buf.Length);
            buf = newbuf;
        }

如果它内置在x64 / AnyCPU中并从控制台运行 - 一切正常。

如果它是跨x86构建的 - 它在控制台中失败了。

如果你说它是内置x64的Page_Load,并且是从VS.Net网络服务器打开的 - 它会失败。

如果你对IIS做同样的事情 - 一切都很好。

希望这有帮助。

答案 1 :(得分:6)

如果您使用的是默认VS开发服务器,则表示您在x86 / 32位进程中运行代码。如果您使用完整的IIS - 最有可能在IIS中,特定的AppPool配置为在x86(32位模式)下运行,因此地址空间非常有限(除非您将应用程序标记为大地址识别,否则为2GB)。

如果是IIS,请确保已配置应用程序轮询以运行x64(不确定什么是默认值)。确保您的代码目标设置为AnyCPU或x64。

对于独立的C#应用​​程序 - 默认情况下,它们使用x86或AnyCPU / Prefer x86进行编译 - 将目标平台更改为x64。

要获得对IIS的x64支持,您可以install full IIS或从Download IIS 8.0 Express安装IIS Express 8.0(Windows 7附带的7.5只是32位)。

附注: