Краткий ответ
Чтобы узнать, насколько велик объект, я бы использовал профилировщик. Например, в YourKit вы можете найти объект, а затем заставить его рассчитать его глубокий размер. Это даст вам четкое представление о том, сколько памяти было бы использовано, если бы объект был изолирован, и имеет консервативный размер для объекта.
Придирки
Если части объекта повторно используются в других структурах, например Строковые литералы, вы не освободите столько памяти, отбросив ее. Фактически, отбрасывание одной ссылки на HashMap может вообще не освободить память.
А как насчет сериализации?
Сериализация объекта - один из подходов к получению оценки, но он может быть диким, так как издержки сериализации и кодировка различаются в памяти и в байтовом потоке. Сколько памяти используется, зависит от JVM (и от того, использует ли она 32/64-битные ссылки), но формат сериализации всегда одинаков.
, например
В JVM от Sun / Oracle Integer может принимать 16 байтов для заголовка, 4 байта для числа и заполнение 4 байта (объекты выровнены в памяти по 8 байтов), всего 24 байта. Однако, если вы сериализуете одно целое число, оно занимает 81 байт, сериализует два целых числа и 91 байт. то есть размер первого целого числа надувается, а второе целое меньше того, что используется в памяти.
Строка - гораздо более сложный пример. В JVM Sun / Oracle он содержит значения 3 int
и ссылку char[]
. Таким образом, вы можете предположить, что он использует 16-байтовый заголовок плюс 3 * 4 байта для int
с, 4 байта для char[]
, 16 байтов для служебной информации char[]
и затем два байта на символ, выровненные по 8- граница байта ...
Какие флаги могут изменить размер?
Если у вас есть 64-битные ссылки, ссылка char[]
имеет длину 8 байтов, что приводит к заполнению 4 байтами. Если у вас есть 64-битная JVM, вы можете использовать +XX:+UseCompressedOops
для использования 32-битных ссылок. (Посмотрите, что размер бит JVM сам по себе не говорит о размере ссылок)
Если у вас есть -XX:+UseCompressedStrings
, JVM будет использовать байт [] вместо массива символов, когда это возможно. Это может немного замедлить ваше приложение, но может значительно увеличить потребление памяти. Когда используется байт [], потребляемая память составляет 1 байт на символ. ;) Примечание: для строки из 4 символов, как в примере, используемый размер такой же из-за 8-байтовой границы.
Что вы подразумеваете под "размером"?
Как уже указывалось, HashMap и List более сложны, поскольку многие, если не все, строки могут использоваться повторно, возможно, строковые литералы. То, что вы подразумеваете под «размером», зависит от того, как он используется. т.е. сколько памяти будет использовать структура в одиночку? Сколько было бы освобождено, если бы структура была отброшена? Сколько памяти будет использовано, если вы скопируете структуру? На эти вопросы могут быть разные ответы.
Что вы можете сделать без профилировщика?
Если вы можете определить, что вероятный консервативный размер достаточно мал, точный размер не имеет значения. В консервативном случае, скорее всего, вы создадите каждую строку и запись с нуля. (Скорее всего, HashMap может вместить 1 миллиард записей, даже если он пуст. Строки с одним символом могут быть подстрокой строки с 2 миллиардами символов)
Вы можете выполнить System.gc (), взять свободную память, создать объекты, выполнить другой System.gc () и посмотреть, насколько уменьшилась свободная память. Возможно, вам придется создавать объект много раз и брать среднее значение. Повторите это упражнение много раз, но оно может дать вам правильное представление.
(Кстати, хотя System.gc () является лишь подсказкой, JVM Sun / Oracle будет выполнять полный GC каждый раз по умолчанию)