Пространство, необходимое для хранения в памяти самого большого целочисленного массива

Jan 04 2021

Я просматриваю алгоритм, и он хранит массив целых чисел, размер ввода динамический. Так что по моим подсчетам это может занять до

  integer MAX_VALUE  * int size  = ?   
      2^31 integers  * 4 bytes   = ?
2147483648 integers  * 4 bytes   = 8 Gigabytes

Это правильный расчет? будет ли JVM использовать это непрерывное пространство для хранения массива int или есть другие вещи, которые нужно учитывать?

Ответы

3 Eugene Jan 05 2021 at 01:39

Теоретический размер массива будет:

  • numberOfElementsInTheArray * 4 байта

  • 12 байт заголовков ( int[]это объект). На самом деле размер заголовков зависит от используемых вами флагов и от версии JVM, в которой вы запускаете этот

  • 4 байта для хранения lengthмассива

  • обивка.

Например: (для этого я буду использовать JOL ):

    int [] x = new int[10];
    for(int i=0;i<10;++i){
        x[i] = 9999;
    }
    System.out.println(GraphLayout.parseInstance((Object)x).toPrintable()); 

выведет:

 [I@7a81197dd object externals:
      ADDRESS       SIZE TYPE PATH                           VALUE
    70fe45268         56 [I                                  [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999]

Итак, в нем есть 56 bytes:

  • 40 для самих значений (10 целых * 4 байта)
  • 12 для заголовков
  • 4 для длины
  • 0 для заполнения

Если вы измените этот массив на Integer, все кардинально изменится. Integerявляется объектом, поэтому вы будете хранить ссылку внутри массива (который может быть 4или 8байтами, в зависимости от UseCompressedOopsфлага), плюс для каждого Integerэкземпляра потребуется 2 заголовка (каждый Integerявляется объектом).

    Integer[] y = new Integer[10];
    for(int i=0;i<10;++i){
        y[i] = 9999;
    }

    System.out.println(GraphLayout.parseInstance((Object)y).toFootprint());

который покажет:

   [Ljava.lang.Integer;@369f73a2d footprint:
 COUNT       AVG       SUM   DESCRIPTION
     1        56        56   [Ljava.lang.Integer;
    10        16       160   java.lang.Integer
    11                 216   (total)

Всего 216 bytes:

  • 4 байта на каждую ссылку (я UseCompressedOopвключил), всего 40 байтов
  • Заголовки массива 12 байтов
  • Длина массива 4 байта
  • Заполнение 0 байтов

Каждая ссылка из этого массива указывает на Integer, каждый из этих объектов будет иметь 16 bytes:

  • 4 байта для внутренней, которую intони держат
  • Заголовки 12 байтов
  • Заполнение 0 байтов
1 BasilBourque Jan 04 2021 at 15:23

Максимальный размер массива < Integer.MAX_VALUE

Нет, ваш максимум неверен.

Ограничение на количество элементов в массиве в Java немного меньше Integer.MAX_VALUE(2 147 483 647), в зависимости от версии Java, ОС хоста и способа компиляции Java. См. Ответ Ивана Мамонтова на вопрос, почему я не могу создать массив большого размера? .

Да, самый большой массив int≈ 8 гигов

Таким образом, размер максимального массива intбудет примерно ( Integer.MAX_VALUE - 8L ) * 32Lбит, что составляет 68 719 476 448 бит, что составляет 8 589 934 556 октетов.

Так что да, около 8 гигов памяти. И помните: это непрерывная память для массива. Так:

  • Для создания такого массива со стороны JVM и ОС хоста может потребоваться значительная работа, в зависимости от того, насколько фрагментирована память в данный момент во время выполнения.
  • Если аппаратное обеспечение хоста не имеет достаточного количества реальной памяти, вы попадете в виртуальную память, где результирующее разбиение на страницы может привести к ужасной производительности.

Всегда проводите тесты в реальных условиях, если вы действительно выходите за эти рамки в своей работе. И вы можете рассмотреть альтернативные реализации Java, предназначенные для очень большой памяти, такие как Zing от Azul Systems.