Объем памяти массивов int [] и Integer [] - PullRequest
2 голосов
/ 21 мая 2011

Я пытаюсь создать массив целых чисел (я пытался с собственным объектом, но то же самое случилось с int), размером 30 миллионов.я продолжаю получать «OutOfMemoryError: пространство кучи Java»

Integer [] index = new Integer[30000000];
for (int i = 0 ; i < 30000000 ; i++){
    index[i] = i;
}

я проверил общее пространство кучи, используя «Runtime.getRuntime (). totalMemory ()» и «maxMemory ()», и увидел, что я начинаю с64 МБ, максимальный - 900+ МБ, и во время бега я получаю 900+ на куче и разгроме.

теперь я знаю, что Integer занимает 4 байта, поэтому даже если я умножу 30 * 4 * 1000000, я все равно получу только около 150-100 мега.

, если я попробую с примитивным типом,как int, это работает.

как я могу это исправить?

Ответы [ 5 ]

7 голосов
/ 21 мая 2011

Java-примитив int займет 4 байта, но если вы используете ValueObject, такой как Integer, он займет гораздо больше места. В зависимости от вашей машины одна ссылка может занимать 32 или 64 бита + размер примитива, который она оборачивает.

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

2 голосов
/ 21 мая 2011

Предположим, что мы говорим о недавней 32-битной Sun JVM.

  • Каждый объект Integer имеет поле 1 int, занимающее 4 байта.
  • Каждый объект Integer имеет 2 слова заголовка, занимающих 8 байтов.
  • Степень детализации выделения (я считаю) 2 слова - 4 байта заполнения.
  • Integer [] имеет 1 ссылку на каждый элемент / позицию массива - 4 байта.

Таким образом, общее количество составляет 20 байтов на элемент массива. 20 х 30 х 1 000 000 = 600 000 000 мегабайт. Теперь добавьте тот факт, что сборщик поколений выделит как минимум 3 пространства объектов разных размеров, и это может легко добавить до 900+ Мбайт.

как я могу это исправить?

  • Используйте int[] вместо Integer.
  • Если значения Integer в основном представляют числа в диапазоне от -128 до + 127, выделите их с помощью Integer.valueOf(int). JLS гарантирует, что Integer объекты, созданные таким образом, будут совместно использованы. (Обратите внимание, что когда Integer создается с помощью автобокса, JLS предусматривает использование valueOf. Таким образом, на самом деле это «исправление» уже применено в вашем примере.)
  • Если ваши значения Integer в основном получены из более крупного, но все еще небольшого домена, рассмотрите возможность реализации собственного кэша для совместного использования Integer объектов.

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

Да, так и будет.

Предположим, ваш класс определен так:

public class MyInt {
    private byte[] bytes = new byte[4];
    ...
}

Каждый MyInt будет занимать:

  • MyInt слова заголовка - 8 байтов
  • MyInt.bytes поле - 4 байта
  • Заполнение - 4 байта
  • Заголовочные слова для байтового массива - 12 байтов
  • Содержимое массива - 4 байта

Теперь добавьте пространство, занятое ссылкой MyInt:

  • Ссылка на каждый MyInt - 4 байта

Итого - 36 байт на MyInt элемент MyInt[].

Сравните это с 20 байтами на Integer элемент Integer[] или 4 байтами на int элемент int[].

0 голосов
/ 22 мая 2011

Это не то, что вы ищете, но оптимальное решение - использовать функцию вместо массива в этом простом примере.

static int index(int num) {
    return num;
}

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

0 голосов
/ 21 мая 2011

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

0 голосов
/ 21 мая 2011

Integer - это объект, который займет более 4 байтов. Насколько больше зависит от реализации. Вам действительно нужно Integer? Единственное преимущество в том, что оно может быть null. Возможно, вы могли бы использовать «дозорное значение» вместо этого; скажем, -1 или Integer.MIN_VALUE.

...