64位.Net应用程序中的内存限制是什么?

21

在我的笔记本电脑上,运行64位的Windows 7操作系统并且有2GB的可用内存(根据任务管理器的报告),我可以执行以下操作:

var x = new Dictionary<Guid, decimal>( 30 * 1024 *1024 );

如果我手头没有更多RAM的电脑,我想知道这个程序是否可以在有4Gb可用内存的电脑上扩展,我将能够分配60M的项目而不是“仅仅”30M,等等?

或者说,除了不能分配大于2GB的单个对象外(受.Net和/或Windows限制),我还会遇到其他限制吗?

更新:好的,所以我不允许分配大于2GB的单个对象。这很重要!但是我当然很好奇,是否可以通过分配像这样的2GB块来完全利用所有内存:

  var x = new List<Dictionary<Guid, decimal>>();
  for ( var i = 0 ; i < 10 ; i++ )
    x.Add( new Dictionary<Guid, decimal>( 30 * 1024 *1024 ) );

如果电脑有超过20GB的空余内存,这个方法是否可行?

2个回答

18

在.NET中,所有对象都有一个2 GiB的限制,您不能创建超过2 GiB的单个对象。如果您需要更大的对象,则需要确保该对象由小于2 GiB的部分构建,因此您不能拥有连续位大于2 GiB的数组或单个长度大于512 MiB的字符串。我对字符串不是完全确定,但我已经进行了一些测试,并在尝试分配大于512 MiB的字符串时遇到了OutOfMemoryExceptions。

这些限制受堆碎片化的影响,即使GC尝试压缩堆,大型对象(大约为80K左右的任意交叉点)最终会进入不被压缩的大对象堆中。严格来说,如果您可以将短暂的分配保持在此阈值以下,则对于您的整体GC内存管理和性能而言,这将更好。


非常感谢您提供的信息!我已经更新了我的问题。在我标记此答案为接受之前,请随意发表评论。 :-) - Dan Byström
@danbystrom - 就像我说的,这取决于堆碎片。当发生这种情况时,大对象堆可能会变得碎片化,导致内存空间中出现空洞(这就是碎片化)。如果一个内存请求无法适应任何可用空洞,并且系统无法释放更多内存,则会遇到OutOfMemoryException,尽管系统总内存有足够的空间。这是由于内存始终被分配为连续的字节块(没有例外)。在这里的一般规则是,保持您的分配短暂且小型。 - John Leidegren
我真的无法回答30 MiB是否是一个好的选择,因为它取决于你的应用程序的内存访问模式。如果您觉得存在问题,可以使用内存分析器等诊断工具来诊断这些问题。如果您还不知道问题在哪里,它们可以提供必要的洞察力。 - John Leidegren
好的,我非常清楚堆碎片问题。我更加好奇的是是否存在虚拟机限制等任何令人不快的意外情况。目前,我将继续假设我能够利用机器上所有可用的空闲内存 - 直到被证明错误! - Dan Byström
我对虚拟机并不是专家,但在我看来,如果正确实现,软件在虚拟机和非虚拟机之间不应该有任何区别。特别是在CLR世界(托管环境)这个抽象层级。 - John Leidegren
显示剩余3条评论

10

更新:随着.NET 4.5的发布,64位系统已经取消了2GB单个对象内存限制。

你需要在你的app.config中设置gcAllowVeryLargeObjects

然而,数组中元素的最大数量仍然是2^32-1。

更多细节请参见CLR 4.0中单个对象大小仍然受限于2 GB吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接