声明大数组时出现OutOfMemoryException异常

18

我需要创建一个相当大的双精度数组,约为12000乘以55000。不幸的是,我收到了内存不足异常。我曾经使用Java进行开发,并且可以更改内存设置。在C#中是否也有这个可能性,还是完全不可能?我正在使用VS 2008。


我建议您考虑一个“主存之外”的数据结构(如数据库)。为什么要存储这样大的双精度数组呢? - bitxwise
1
我也对使用“相当”这个词感到好笑。 - Ray Booysen
没问题,我会将东西持久化到数据库中。 - cs0815
或许可以在设置 LARGE_ADDRESS_AWARE 的 PE 标志时解决这个问题。 - unknown6656
4个回答

31

每个double占用8字节,所以您试图分配一个略大于5GB的单个数组。即使对于64位CLR,CLR也有每个对象限制约为2GB,换句话说,问题不在于可用的总内存量(尽管如果您没有足够的内存,显然会有问题),而在于每个对象的大小。

我建议您将其拆分为较小的数组,或者在某种描述性的外观后面进行拆分。我不认为有任何方法可以规避单个数组的该限制。

编辑:您可以选择使用数组的数组 - 即“嵌套数组”:

double[][] array = new double[12000][];
for (int i = 0; i < array.Length; i++)
{
    array[i] = new double[55000];
}

你认为这样可行吗?

(你不能使用矩形数组 (double[,] ),因为它会有相同的每个对象大小问题。)


1
不要使用一个双精度数组,我认为他的意思是使用二维数组。 - bitxwise
1
虚拟内存不是问题。你试图在2GB的限制下分配5GB的内存。 :) - Ray Booysen
1
如果数据非常稀疏,那么它们可能根本不应该在数组中。使用Dictionary<int, double>来存储数据。只要大约一半的值为空,它可能会使用更少的空间。 - Servy
2
@Servy:鉴于接受了,我怀疑OP实际上对使用相当多的内存的锯齿数组感到满意。现在5GB并不是那么多了 :) - Jon Skeet
这个2GB的限制更多是因为在RAM中获得2GB连续内存块总是很困难,还是因为32位操作系统中一个应用程序的单个对象占用2GB内存空间看起来不可行。我持后一种观点。32位操作系统只能寻址4GB内存。在寻址主内存时已经有了3GB的限制,然后你还需要操作系统保留空间,再加上正在运行的应用程序空间。我相信即使CLR最初允许每个对象超过2GB,它也永远不会可行。 - RBT
显示剩余5条评论

11

由于您无法创建大于2GB的对象,因此可以尝试使用MemoryMappedFile来处理所需大小的内存块。


var data = MemoryMappedFile.CreateNew("big data", 12000L * 55000L);
var view = data.CreateViewAccessor();
var rnd = new Random();
for (var i = 0L; i < 12000L; ++i) { for (var j = 0L; j < 55000L; ++j) { var input = rnd.NextDouble(); view.Write<double>(i * 55000L + j, ref input); } }
这段代码创建了一个名为"big data"的内存映射文件,大小为12000L*55000L。使用Random类生成随机数并将其写入该内存映射文件中,最终生成一个双精度浮点数数组。

6

0

可能是你的内存不足(关闭一些程序)或者你已经达到了内存分配限制(大约2GB),这个内存需要是一个连续的块。你可以使用64位机器,这样你将有更多的可用内存,或者我认为你可以使应用程序具有大地址感知能力(如果在这种情况下可能的话,搜索一下就会告诉你如何做)。

相信你可以在Boot.ini文件中添加/3GB开关来实现大地址感知。


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