数组的大小是否受到int上限(2147483647)的限制?

发布于 2024-07-14 09:13:56 字数 535 浏览 7 评论 0原文

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

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

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

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

那么,我可以有更大的数组吗?

编辑: 这是一个阿特金筛,你知道,所以我只想要一个非常大的: D

I'm doing some Project Euler exercises and I've run into a scenario where I have want arrays which are larger than 2,147,483,647 (the upper limit of int in C#).

Sure these are large arrays, but for instance, I can't do this

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

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

So, can I have bigger arrays?

EDIT:
It was for a Sieve of Atkin, you know, so I just wanted a really big one :D

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

時窥 2024-07-21 09:13:56

每当您使用这么大的数组时,您可能应该尝试找到更好的问题解决方案。 但话虽这么说,我仍然会尝试回答你的问题。

正如这篇文章中提到的,有一个 2 .Net 中任何对象的 GB 限制。 适用于所有 x86、x64 和 IA64。

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

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

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

如果您无法一次分配全部数组列表,您可以分部分分配它。

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

Anytime you are working with an array this big, you should probably try to find a better solution to the problem. But that being said I'll still attempt to answer your question.

As mentioned in this article there is a 2 GB limit on any object in .Net. For all x86, x64 and IA64.

As with 32-bit Windows operating
systems, there is a 2GB limit on the
size of an object you can create while
running a 64-bit managed application
on a 64-bit Windows operating system.

Also if you define an array too big on the stack, you will have a stack overflow. If you define the array on the heap, it will try to allocate it all in one big continuous block. It would be better to use an ArrayList which has implicit dynamic allocation on the heap. This will not allow you to get past the 2GB, but will probably allow you to get closer to it.

I think the stack size limit will be bigger only if you are using an x64 or IA64 architecture and operating system. Using x64 or IA64 you will have 64-bit allocatable memory instead of 32-bit.

If you are not able to allocate the array list all at once, you can probably allocate it in parts.

Using an array list and adding 1 object at a time on an x64 Windows 2008 machine with 6GB of RAM, the most I can get the ArrayList to is size: 134217728. So I really think you have to find a better solution to your problem that does not use as much memory. Perhaps writing to a file instead of using RAM.

送君千里 2024-07-21 09:13:56

据我所知,即使在 64 位上,数组限制也固定为 int32。 单个对象的最大大小有上限。 然而,你可以很容易地得到一个漂亮的大锯齿状数组。

更差; 因为 x64 中的引用更大,所以对于 ref 类型数组,您实际上在单个数组中获得更少元素。

请参阅此处

我收到了很多询问,例如
为什么64位版本的2.0
.Net 运行时仍然具有数组最大值
大小限制为 2GB。 鉴于它
似乎是最近的热门话题
想了一些背景和
讨论获得的选项
围绕这个限制是有序的。

首先一些背景知识; 在2.0
.Net 运行时 (CLR) 版本
做出了有意识的设计决定
保持允许的最大对象大小
在 2GB 的 GC 堆中,甚至在
64 位版本的运行时。 这是
和现在的1.1一样
32位CLR的实现,
然而你很难
实际上分配了2GB
32 位 CLR 上的对象,因为
虚拟地址空间简直太
碎片化以实际找到 2GB
洞。 一般人都不是
特别关心创造
类型将大于 2GB,当
实例化(或任何接近的地方),
然而,由于数组只是一个
特殊类型的托管类型是
它们在托管堆中创建
也受到这个限制。


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

The array limit is, afaik, fixed as int32 even on 64-bit. There is a cap on the maximum size of a single object. However, you could have a nice big jagged array quite easily.

Worse; because references are larger in x64, for ref-type arrays you actually get less elements in a single array.

See here:

I’ve received a number of queries as
to why the 64-bit version of the 2.0
.Net runtime still has array maximum
sizes limited to 2GB. Given that it
seems to be a hot topic of late I
figured a little background and a
discussion of the options to get
around this limitation was in order.

First some background; in the 2.0
version of the .Net runtime (CLR) we
made a conscious design decision to
keep the maximum object size allowed
in the GC Heap at 2GB, even on the
64-bit version of the runtime. This is
the same as the current 1.1
implementation of the 32-bit CLR,
however you would be hard pressed to
actually manage to allocate a 2GB
object on the 32-bit CLR because the
virtual address space is simply too
fragmented to realistically find a 2GB
hole. Generally people aren’t
particularly concerned with creating
types that would be >2GB when
instantiated (or anywhere close),
however since arrays are just a
special kind of managed type which are
created within the managed heap they
also suffer from this limitation.


It should be noted that in .NET 4.5 the memory size limit is optionally removed by the gcAllowVeryLargeObjects flag, however, this doesn't change the maximum dimension size. The key point is that if you have arrays of a custom type, or multi-dimension arrays, then you can now go beyond 2GB in memory size.

烛影斜 2024-07-21 09:13:56

您根本不需要那么大的数组。

当你的方法遇到资源问题时,不要只看如何扩展资源,还要看方法。 :)

这是一个使用 3 MB 缓冲区来使用埃拉托斯特尼筛法计算素数的类。 该类会跟踪您计算素数的程度,并且当需要扩展范围时,它会创建一个缓冲区来测试另外 300 万个数字。

它将找到的素数保存在列表中,当范围扩大时,以前的素数将用于排除缓冲区中的数字。

我做了一些测试,大约 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;
   }

}

You don't need an array that large at all.

When your method runs into resource problems, don't just look at how to expand the resources, look at the method also. :)

Here's a class that uses a 3 MB buffer to calculate primes using the sieve of Eratosthenes. The class keeps track of how far you have calculated primes, and when the range needs to be expanded it creates a buffer to test another 3 million numbers.

It keeps the found prime numbers in a list, and when the range is expanded the previos primes are used to rule out numbers in the buffer.

I did some testing, and a buffer around 3 MB is most efficient.

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;
   }

}
拒绝两难 2024-07-21 09:13:56

我相信即使在 64 位 CLR 中,每个对象也有 2GB(或者可能是 1GB - 我记不清了)的限制。 这将阻止您创建更大的数组。 Array.CreateInstance 仅采用 Int32 大小参数这一事实也很具有启发性。

从更广泛的角度来看,我怀疑如果您需要那么大的数组,您确实应该改变解决问题的方式。

I believe that even within a 64 bit CLR, there's a limit of 2GB (or possibly 1GB - I can't remember exactly) per object. That would prevent you from creating a larger array. The fact that Array.CreateInstance only takes Int32 arguments for sizes is suggestive too.

On a broader note, I suspect that if you need arrays that large you should really change how you're approaching the problem.

咿呀咿呀哟 2024-07-21 09:13:56

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

I'm very much a newbie with C# (i.e. learning it this week), so I'm not sure of the exact details of how ArrayList is implemented. However, I would guess that as you haven't defined a type for the ArrayList example, then the array would be allocated as an array of object references. This might well mean that you are actually allocating 4-8Gb of memory depending on the architecture.

蓝咒 2024-07-21 09:13:56

根据 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;
    }

According to MSDN, the index for array of bytes cannot be greater than 2147483591. For .NET prior to 4.5 it also was a memory limit for an array. In .NET 4.5 this maximum is the same, but for other types it can be up to 2146435071.

This is the code for illustration:

    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;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文