我的内存是4G物理,但即使我只创建1.5G内存对象,为什么我的内存异常。有什么想法吗? (我在同一时间看到,在任务管理器的性能选项卡中,内存未被完全占用,我也可以在这里输入 - 所以内存实际上并不低,所以我认为我遇到了其他一些内存限制)?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestBigMemoryv1
{
class MemoryHolderFoo
{
static Random seed = new Random();
public Int32 holder1;
public Int32 holder2;
public Int64 holder3;
public MemoryHolderFoo()
{
// prevent from optimized out
holder1 = (Int32)seed.NextDouble();
holder2 = (Int32)seed.NextDouble();
holder3 = (Int64)seed.NextDouble();
}
}
class Program
{
static int MemoryThreshold = 1500; //M
static void Main(string[] args)
{
int persize = 16;
int number = MemoryThreshold * 1000 * 1000/ persize;
MemoryHolderFoo[] pool = new MemoryHolderFoo[number];
for (int i = 0; i < number; i++)
{
pool[i] = new MemoryHolderFoo();
if (i % 10000 == 0)
{
Console.Write(".");
}
}
return;
}
}
}
答案 0 :(得分:40)
在普通的32位Windows应用程序中,该进程只有2GB的可寻址内存。这与可用的物理内存量无关。
2GB可用,但1.5是你可以分配的最大值。关键是您的代码不是该过程中运行的唯一代码。另一个.5 GB可能是CLR加上碎片的过程。
在64位进程的.Net 4.5中更新:如果启用gcAllowVeryLargeObjects设置,则可以使用大型数组:
在64位平台上,启用总大小超过2千兆字节(GB)的阵列。 数组中的最大元素数是UInt32.MaxValue。
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
答案 1 :(得分:10)
除了其他要点之外;如果要访问大量内存,请考虑x64 - 但请注意,最大单个对象大小仍为2GB。并且因为x64中的引用较大,这意味着您实际上为引用类型获得了较小的最大数组/列表大小。当然,当你达到这个极限时,你可能还是做错了!
其他选择:
(显然两者与进程内存相比都有性能差异)
更新:在4.5之前的.NET版本中,最大对象大小为2GB。从4.5开始,如果启用gcAllowVeryLargeObjects,您可以分配更大的对象。请注意,string
的限制不受影响,但“数组”也应该包含“列表”,因为列表由数组支持。
答案 2 :(得分:5)
只是添加到之前的回复中:您可以超越使用/ 3Gb [和可选的userva]启动标志启动的系统的2Gb限制。
答案 3 :(得分:5)
检查您是否正在构建64位进程,而不是32位进程,这是Visual Studio的默认编译模式。为此,右键单击您的项目,属性 - &gt;构建 - &gt;平台目标:x64。与任何32位进程一样,以32位编译的Visual Studio应用程序的虚拟内存限制为2GB。
每个进程都有自己的虚拟内存,称为地址空间,它将映射所执行的代码及其操作的数据。 32位进程使用32位虚拟内存地址指针,它为32位进程可以处理的虚拟内存量创建4GB(2 ^ 32)的绝对上限。但是,操作系统需要一半(引用自己的代码和数据),为每个进程创建2GB的限制。如果您的32位应用程序尝试消耗超过其整个2GB的地址空间,它将返回“System.OutOfMemory”,即使您的计算机的物理内存未满。
64位进程没有此限制,因为它们使用64位指针,因此它们的理论最大地址空间为16艾字节(2 ^ 64)。实际上,Windows x64将进程的虚拟内存限制为8TB。然后,内存限制问题的解决方案是以64位编译。
但是,默认情况下,Visual Studio中对象的大小仍限制为2GB。您将能够创建多个组合大小将大于2GB的阵列,但默认情况下不能创建大于2GB的阵列。希望如果您仍然想要创建大于2GB的数组,可以通过向app.config文件添加以下代码来实现:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
答案 4 :(得分:4)
正如其他海报提到的那样,你有一个32位应用程序的最大2Gb可寻址内存。不要忘记开销。你正在创建一个包含9300万个对象的数组 - 如果每个对象恰好有4个字节的开销,那就是额外的350Mb内存。
答案 5 :(得分:4)
还有一件事需要注意;某些.NET对象需要“连续”内存。即如果你正在尝试分配一个大型数组,系统可能不仅需要在你的进程中有足够的可用内存,而且还需要所有可用内存都在一个大块中......不幸的是,进程内存会随着时间的推移而变得支离破碎,所以这可能是不可用。
有些对象/数据类型有这个要求,有些没有...我不记得是哪些,但我似乎记得StringBuilder和MemoryStream有不同的要求。
答案 6 :(得分:3)
在32位Windows操作系统上,单个应用程序可以访问的最大“用户模式”内存为2GB ......假设您的盒子上有4GB内存。
Unmanaged VC++ Application's memory consumption on windows server
http://blogs.technet.com/markrussinovich/archive/2008/07/21/3092070.aspx
(你问这个很有趣,因为我昨天几乎要问同样的事情......)