我在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。所以我想知道是否需要设置一些全局设置才能使其正常工作?
以下是项目配置设置的屏幕截图:
答案 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位)。
附注: