21

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

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 个字节时抛出:

分配大小=268435456

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

这是该项目的配置设置的屏幕截图: 在此处输入图像描述

4

2 回答 2

32

Short answer - dev server is 32bit process.

Long answer for "why just 256Mb?"

First of all, let's understand how it works.

MemoryStream has internal byte[] buffer to keep all the data. It cannot predict exact size of this buffer, so it just initializes it with some initial value.

Position and Length properties don't reflect actual buffer size - they are logical values to reflect how many bytes is written, and easily may be smaller than actual physical buffer size.

When this internal buffer can not fit all the data, it should be "re-sized", but in real life it means creating new buffer twice as size as previous one, and then copying data from old buffer to new buffer.

So, if the length of your buffer is 256Mb, and you need new data to be written, this means that .Net need to find yet another 512Mb block of data - having all the rest in place, so heap should be at least 768Mb on the moment of memory allocation when you receive OutOfMemory.

Also please notice that by default no single object, including arrays, in .Net can take more than 2Gb in size.

Ok, so here is the sample piece which simulates what's happening:

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

If it built in x64/AnyCPU and runs from console - everything is ok.

If it built across x86 - it fails in console.

If you put it to say Page_Load, built in x64, and open from VS.Net web server - it fails.

If you do the same with IIS - everything is ok.

Hope this helps.

于 2013-03-24T10:02:59.000 回答
6

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

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

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

要获得对 IIS 的 x64 支持,您可以从下载 IIS 8.0 Express安装完整的 IIS或安装 IIS Express 8.0(Windows 7 附带的 7.5 仅为 32 位)。

旁注:

于 2013-03-24T04:14:25.960 回答