Ограничен ли размер массива верхним пределом int (2147483647)? - PullRequest
5 голосов
/ 21 февраля 2009

Я выполняю 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); 

Итак, я могу иметь большие массивы?

EDIT: Знаете, это было для Sieve of Atkin , поэтому я просто хотел действительно большой: D

Ответы [ 6 ]

12 голосов
/ 21 февраля 2009

Каждый раз, когда вы работаете с таким большим массивом, вам, вероятно, следует попытаться найти лучшее решение проблемы. Но, как говорится, я все же попытаюсь ответить на ваш вопрос.

Как упоминалось в этой статье , для любого объекта в .Net существует ограничение в 2 ГБ. Для всех x86, x64 и IA64.

Как и при работе с 32-битной Windows систем, существует ограничение в 2 ГБ размер объекта, который вы можете создать в то время как запуск 64-битного управляемого приложения в 64-битной операционной системе Windows.

Также, если вы определите слишком большой массив в стеке, у вас будет переполнение стека. Если вы определите массив в куче, он попытается разместить все это в одном большом непрерывном блоке. Было бы лучше использовать ArrayList, который имеет неявное динамическое распределение в куче. Это не позволит вам преодолеть 2 ГБ, но, вероятно, позволит вам приблизиться к нему.

Я думаю, что предел размера стека будет больше, только если вы используете архитектуру и операционную систему x64 или IA64. Используя x64 или IA64, вы будете иметь 64-битную выделяемую память вместо 32-битной.

Если вы не можете выделить список массивов сразу, вы, вероятно, можете выделить его по частям.

Используя список массивов и добавляя по одному объекту за раз на компьютере с Windows x 2008 с 64 ГБ ОЗУ, максимум, что я могу получить для ArrayList - это размер: 134217728. Поэтому я действительно думаю, что вам нужно найти лучшее решение для Ваша проблема, которая не использует столько памяти. Возможно запись в файл вместо использования оперативной памяти.

8 голосов
/ 21 февраля 2009

Ограничение массива, afaik, фиксировано как int32 даже на 64-битной версии. Существует ограничение на максимальный размер одного объекта. Тем не менее, вы можете легко получить хороший большой зубчатый массив.

Хуже; поскольку в x64 ссылки больше, для массивов ref-типа вы фактически получаете меньше элементов в одном массиве.

См. здесь :

Я получил несколько запросов как почему 64-битная версия 2.0 .Net Runtime по-прежнему имеет максимум массива Размеры ограничены до 2 ГБ. Учитывая, что это кажется, горячая тема в последнее время я понял немного фона и обсуждение вариантов получения вокруг этого ограничения было в порядке.

Сначала немного предыстории; в 2.0 версия .Net runtime (CLR) мы принял сознательное дизайнерское решение сохранить максимально допустимый размер объекта в GC Heap на 2Гб, даже на 64-битная версия среды выполнения. Это такой же как текущий 1.1 реализация 32-битного CLR, Однако вам будет трудно на самом деле удается выделить 2 ГБ объект на 32-битном CLR, потому что виртуальное адресное пространство просто слишком фрагментирован, чтобы реально найти 2 ГБ отверстие. Обычно люди не особенно касается создания типы, которые будут> 2 ГБ, когда экземпляр (или где-то близко), Однако так как массивы просто особый вид управляемого типа, который созданные в управляемой куче они также страдают от этого ограничения.


Следует отметить, что в .NET 4.5 ограничение памяти необязательно снимается флагом gcAllowVeryLargeObjects , однако это не меняет максимальное измерение * Размер 1023 *. Ключевым моментом является то, что если у вас есть массивы пользовательского типа или многомерные массивы, то теперь вы можете превысить 2 ГБ в объеме памяти.

6 голосов
/ 22 февраля 2009

Вам вообще не нужен такой большой массив.

Когда у вашего метода возникают проблемы с ресурсами, не просто смотрите, как расширить ресурсы, но и посмотрите на метод. :)

Вот класс, который использует буфер 3 МБ для вычисления простых чисел, используя сито Эратосфена. Класс отслеживает, как далеко вы вычислили простые числа, и когда необходимо расширить диапазон, он создает буфер для проверки еще 3 миллионов чисел.

Хранит найденные простые числа в списке, а когда диапазон расширяется, простые числа используются для исключения чисел в буфере.

Я провел некоторое тестирование, и буфер около 3 МБ наиболее эффективен.

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

}
2 голосов
/ 21 февраля 2009

Я считаю, что даже в 64-битной среде CLR существует ограничение в 2 ГБ (или, возможно, 1 ГБ - точно не помню) на объект. Это помешает вам создать больший массив. Тот факт, что Array.CreateInstance принимает только аргументы Int32 для размеров, также наводит на мысль.

В более широком смысле, я подозреваю, что если вам нужны массивы такого размера, вам действительно следует изменить подход к проблеме.

1 голос
/ 22 февраля 2009

Я очень новичок в C # (то есть изучаю его на этой неделе), поэтому я не уверен в точных деталях того, как реализован ArrayList. Тем не менее, я бы предположил, что, поскольку вы не определили тип для примера ArrayList, тогда массив будет выделен как массив ссылок на объекты. Это может означать, что вы на самом деле выделяете 4–8 ГБ памяти в зависимости от архитектуры.

0 голосов
/ 16 сентября 2014

Согласно MSDN , индекс для массива байтов не может быть больше 2147483591. Для .NET до 4.5 это также был предел памяти для массива. В .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;
    }
...