C# 填充 MemoryStream 时出现 OutOfMemoryException:16GB 系统上的 256MB 分配

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15595061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 17:19:09  来源:igfitidea点击:

OutOfMemoryException while populating MemoryStream: 256MB allocation on 16GB system

c#asp.netmemoryout-of-memory

提问by c00000fd

I'm running the following method on my development IIS server (from VS2010 IDE) on a 64-bit Windows 7 machine with 16GB of installed RAM:

我在安装了 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;
}

and I get the System.OutOfMemoryExceptionon this line:

System.OutOfMemoryException在这条线上得到了:

ms.Write(buff, 0, nSz);

That is thrown when 268435456 bytes are allocated:

当分配 268435456 字节时抛出:

Alloc size=268435456

分配大小=268435456

which is 0x10000000 or 256 MB. So I'm wondering if there's some global setting that I need to set to make it work?

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

Here's a screenshot of the configuration setting for the project: enter image description here

这是项目的配置设置的屏幕截图: 在此处输入图片说明

采纳答案by Lanorkin

Short answer- dev server is 32bit process.

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

Long answer for "why just 256Mb?"

“为什么只有 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.

MemoryStream 具有内部 byte[] 缓冲区来保存所有数据。它无法预测此缓冲区的确切大小,因此它只是使用某个初始值对其进行初始化。

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 buffertwice 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.

因此,如果您的缓冲区长度为 256Mb,并且您需要写入新数据,这意味着 .Net 需要找到另一个 512Mb 的数据块 - 将所有其他数据块都准备好,因此堆应该至少为 768Mb收到 OutOfMemory 时的内存分配时刻。

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

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

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.

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

If it built across x86 - it fails in console.

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

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

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

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

如果您对 IIS 执行相同操作,则一切正常。

Hope this helps.

希望这可以帮助。

回答by Alexei Levenkov

If you are using default VS development server you are running code in x86/32 bit process. If you are using full IIS - most likely in IIS particular AppPool is configured to runs in x86 (32 bit mode) and as result have very limited address space (2GB unless you have marked your application as Large Address Aware).

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

In case of IIS make sure you have configured app polls to run x64 (not sure what is default). Make sure your code is target is set to AnyCPU or x64.

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

For standalone C# applications - by default they are compiled with x86 or AnyCPU/Prefer x86 - change target platform to x64.

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

To get x64 support for IIS you can either install full IISor install IIS Express 8.0 ( 7.5 that comes with Windows 7 is 32 bit only) from Download IIS 8.0 Express.

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

Side notes:

旁注: