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