Ограничен ли размер массива верхним пределом int (2147483647)?

StackOverflow https://stackoverflow.com/questions/573692

Вопрос

Я делаю некоторые Проект Эйлер упражнения, и я столкнулся со сценарием, в котором я иметь хотите массивы, размер которых превышает 2,147,483,647 (верхний предел int в C#).

Конечно, это большие массивы, но, например, я не могу этого сделать

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

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

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

Редактировать:Это было для Сито Аткина, ты знаешь, так что я просто хотел действительно большой : D

Это было полезно?

Решение

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

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

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

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

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

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

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

Другие советы

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

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

Видишь здесь:

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

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


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

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

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

Вот класс, который использует буфер размером 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;
   }

}

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

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

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

Согласно 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;
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top