Затраты памяти 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()
чтобы получить текущий размер базового массива.
Большая проблема с вашим подходом - взаимодействие с сборщиком мусора. Это в основном делает любой тест, как вы предложили, совершенно непрозрачным снаружи.
В качестве мысленного эксперимента, если вы хотите сделать это, вы должны
- запусти свою JVM и сделай пару глобальных сборщиков мусора, чтобы избавиться от всего лишнего
- Измерьте размер кучи и представление Java о том, сколько в ней свободного места.
- Запустите свой тест
- GC пару раз
- Повторите измерения из шага № 2
После всего этого и немного математики вы будете ближе, но все же не правы. Единственное реальное решение - фактически спросить реализацию, как уже упоминали другие люди. Или выяснить это из знания реализации.
Память, используемая arraylist, немного расплывчата.
Возьмите дамп кучи процесса на соответствующем этапе - после того, как значения полностью назначены. Затем используйте такие инструменты, как анализатор памяти (из Eclipse).
Вы заполняете мелкие и сохраняемые размеры кучи.
В качестве примечания: поскольку вы точно знаете, сколько объектов будет в вашем ArrayList, почему бы просто не использовать массив []? Изменится ли количество объектов там?