数组的大小是否受int的上限(2147483647)约束?

时间:2009-02-21 20:31:50

标签: c# arrays int integer-overflow

我正在进行一些Project Euler练习,我遇到了一个场景,我 想要的数组大于2,147,483,647(int的上限C#)。

当然这些是大型数组,但是,例如,我不能这样做

// fails
bool[] BigArray = new BigArray[2147483648];

// also fails, cannot convert uint to int
ArrayList BigArrayList = new ArrayList(2147483648); 

那么,我可以拥有更大的阵列吗?

编辑: 你知道,这是Sieve of Atkin,所以我只想要一个非常大的:D

6 个答案:

答案 0 :(得分:12)

任何时候你正在使用这么大的数组,你应该尝试找到一个更好的问题解决方案。但话虽如此,我仍会尝试回答你的问题。

如此article中所述,.Net中的任何对象都有2 GB的限制。适用于所有x86,x64和IA64。

  

与32位Windows操作一样   系统,有2GB的限制   您可以创建的对象的大小   运行64位托管应用程序   在64位Windows操作系统上。

此外,如果在堆栈上定义一个太大的数组,则会出现堆栈溢出。如果在堆上定义数组,它将尝试在一个大的连续块中分配它。最好使用在堆上具有隐式动态分配的ArrayList。这不会让你超过2GB,但可能会让你更接近它。

我认为只有在使用x64或IA64架构和操作系统时,堆栈大小限制才会更大。使用x64或IA64,您将拥有64位可分配内存而不是32位。

如果您无法一次性分配数组列表,则可以将其分配。

使用数组列表并在具有6GB RAM的x64 Windows 2008计算机上一次添加1个对象,我可以获得的最大数量是:134217728。所以我真的认为你必须找到一个更好的解决方案你的问题没有使用尽可能多的内存。也许写入文件而不是使用RAM。

答案 1 :(得分:8)

即使在64位上,数组限制也是固定为int32。单个对象的最大大小上限。但是,你可以很容易地得到一个漂亮的大锯齿阵列。

更糟糕;因为x64中的引用较大,对于ref-type数组,实际上在单个数组中得到 less 元素。

请参阅here

  

我收到了一些查询   为什么是64位版本的2.0   .Net运行时仍然有数组最大值   尺寸限制为2GB。鉴于它   似乎是我迟到的热门话题   想出了一点背景和一点   讨论获得的选择   围绕这个限制是有序的。

     

首先是一些背景;在2.0中   我们的.Net运行时版本(CLR)   做出了有意识的设计决定   保持允许的最大对象大小   在GC堆中2GB,即使在   64位版本的运行时。这是   与目前的1.1相同   实现32位CLR,   但是你会很难受   实际上设法分配2GB   因为32位CLR上的对象   虚拟地址空间也是如此   支离破碎,逼真地找到2GB   洞。一般人不是   特别关注创造   类型为> 2GB时   实例化(或任何接近),   但是因为数组只是一个   特殊的托管类型   在托管堆中创建它们   也受到这种限制。


应该注意的是,在.NET 4.5中,内存大小限制可选地由gcAllowVeryLargeObjects标志删除,但是,这不会更改最大维度尺寸。关键是如果你有自定义类型或多维数组的数组,那么你现在可以超过2GB的内存大小。

答案 2 :(得分:6)

你根本不需要一个大的数组。

当您的方法遇到资源问题时,不要只看看如何扩展资源,也请查看方法。 :)

这是一个使用3 MB缓冲区使用Eratosthenes筛子计算质数的类。该类记录您计算素数的距离,当需要扩展范围时,它会创建一个缓冲区来测试另外300万个数字。

它将找到的素数保存在列表中,当扩展范围时,使用previos素数来排除缓冲区中的数字。

我做了一些测试,大约3 MB的缓冲区效率最高。

public class Primes {

   private const int _blockSize = 3000000;

   private List<long> _primes;
   private long _next;

   public Primes() {
      _primes = new List<long>() { 2, 3, 5, 7, 11, 13, 17, 19 };
      _next = 23;
   }

   private void Expand() {
      bool[] sieve = new bool[_blockSize];
      foreach (long prime in _primes) {
         for (long i = ((_next + prime - 1L) / prime) * prime - _next;
            i < _blockSize; i += prime) {
            sieve[i] = true;
         }
      }
      for (int i = 0; i < _blockSize; i++) {
         if (!sieve[i]) {
            _primes.Add(_next);
            for (long j = i + _next; j < _blockSize; j += _next) {
               sieve[j] = true;
            }
         }
         _next++;
      }
   }

   public long this[int index] {
      get {
         if (index < 0) throw new IndexOutOfRangeException();
         while (index >= _primes.Count) {
            Expand();
         }
         return _primes[index];
      }
   }

   public bool IsPrime(long number) {
      while (_primes[_primes.Count - 1] < number) {
         Expand();
      }
      return _primes.BinarySearch(number) >= 0;
   }

}

答案 3 :(得分:2)

我相信即使在64位CLR中,每个对象也有2GB的限制(或者可能是1GB - 我记不清楚)。这会阻止您创建更大的数组。 Array.CreateInstance只接受大小的Int32参数的事实也是暗示性的。

从更广泛的角度来看,我怀疑如果你需要大的阵列,你应该真正改变你接近问题的方式。

答案 4 :(得分:1)

我是C#的新手(即本周学习它),所以我不确定ArrayList如何实现的具体细节。但是,我猜想,由于您尚未为ArrayList示例定义类型,因此该数组将被分配为对象引用数组。这可能意味着您实际上正在分配4-8Gb的内存,具体取决于架构。

答案 5 :(得分:0)

According to MSDN,字节数组的索引不能大于2147483591.对于4.5之前的.NET,它也是数组的内存限制。在.NET 4.5中,此最大值相同,但对于其他类型,最大值可达2146435071。

这是插图的代码:

    static void Main(string[] args)
    {
        // -----------------------------------------------
        // Pre .NET 4.5 or gcAllowVeryLargeObjects unset
        const int twoGig = 2147483591; // magic number from .NET

        var type = typeof(int);          // type to use
        var size = Marshal.SizeOf(type); // type size
        var num = twoGig / size;         // max element count

        var arr20 = Array.CreateInstance(type, num);
        var arr21 = new byte[num];

        // -----------------------------------------------
        // .NET 4.5 with x64 and gcAllowVeryLargeObjects set
        var arr451 = new byte[2147483591];
        var arr452 = Array.CreateInstance(typeof(int), 2146435071);
        var arr453 = new byte[2146435071]; // another magic number

        return;
    }