Затраты памяти Java

Я хотел бы спросить о накладных расходах памяти в Java, у меня есть большой ArrayList (61 770 элементов), и я пытаюсь вычислить объем памяти, занимаемый каждым элементом (считая объект и его запись ArrayList), профилируя приложение, которое я получаю, что после загрузки всех данных куча занимает ~ 25 Мб. когда ArrayList имеет только 2 элемента, куча занимает ~1 Мб, примерно так:

(24 * 1024 * 1024) / 61 768 = 407 байт.

однако, когда я подсчитываю поля каждого объекта, я получаю 148 байт (не считая ArrayList и предполагая, что int=4,float=4,reference=4), мне любопытно узнать, откуда взялись все эти дополнительные байты от...

я могу предположить, что, поскольку объекты, которые я храню в ArrayList, реализуют интерфейс, они хранят дополнительные значения, может быть, виртуальная машина хранит 4-байтовый указатель на функцию для каждого реализованного метода? Интерфейс, который они реализуют, имеет 20 функций, так что на 80 байтов больше, всего 228 байтов, все еще не близко к измеренным 400 байтов.

любая помощь будет оценена.


вау, спасибо за все отличные ответы.

@Bolo: спасибо за ссылку, с этим классом я измеряю ~350 байт на объект, так что я меньше всего могу подтвердить источник большого использования памяти.

@Yuval A: спасибо за эту презентацию, ценный источник информации.

@Ukko: точка отмечена.

@Jayan: прямо сейчас профилировщик NetBeans выдает мне ошибки, когда я пытаюсь сбросить кучу, попробую позже.

5 ответов

Решение

Эти результаты не удивительны. JVM добавляет огромное количество накладных расходов для каждого объекта.

Примерно вдвое больше ожидаемого размера для одного объекта из-за нехватки памяти в JVM не редкость.

Эта презентация содержит замечательное, подробное объяснение и обзор использования памяти различных структур данных в Java.

ArrayList в основном больше, чем количество элементов. использование getCapacity() чтобы получить текущий размер базового массива.

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

В качестве мысленного эксперимента, если вы хотите сделать это, вы должны

  1. запусти свою JVM и сделай пару глобальных сборщиков мусора, чтобы избавиться от всего лишнего
  2. Измерьте размер кучи и представление Java о том, сколько в ней свободного места.
  3. Запустите свой тест
  4. GC пару раз
  5. Повторите измерения из шага № 2

После всего этого и немного математики вы будете ближе, но все же не правы. Единственное реальное решение - фактически спросить реализацию, как уже упоминали другие люди. Или выяснить это из знания реализации.

Память, используемая arraylist, немного расплывчата.

Возьмите дамп кучи процесса на соответствующем этапе - после того, как значения полностью назначены. Затем используйте такие инструменты, как анализатор памяти (из Eclipse).

Вы заполняете мелкие и сохраняемые размеры кучи.

В качестве примечания: поскольку вы точно знаете, сколько объектов будет в вашем ArrayList, почему бы просто не использовать массив []? Изменится ли количество объектов там?

Другие вопросы по тегам