Является ли пространство памяти, используемое одним объектом со 100 атрибутами, таким же, как у 100 объектов, каждый с одним атрибутом?
Сколько памяти выделено для объекта?
Сколько дополнительного места используется при добавлении атрибута?
Является ли пространство памяти, используемое одним объектом со 100 атрибутами, таким же, как у 100 объектов, каждый с одним атрибутом?
Сколько памяти выделено для объекта?
Сколько дополнительного места используется при добавлении атрибута?
Mindprod отмечает, что на этот вопрос непросто ответить:
JVM может свободно хранить данные внутри себя любым способом, с прямым порядком байтов или прямым порядком байтов, с любым количеством дополнений или накладных расходов, хотя примитивы должны вести себя так, как если бы они имели официальные размеры.
Например, JVM или собственный компилятор могут решили хранитьboolean[]
в виде 64-битных длинных фрагментов, напримерBitSet
. Он не должен вам сообщать, если программа дает одинаковые ответы.
- Он может выделить некоторые временные объекты в стеке.
- Он может полностью исключить оптимизацию некоторых переменных или вызовов методов, заменив их константами.
- Он может создавать версии методов или циклов, то есть компилировать две версии метода, каждая из которых оптимизирована для определенной ситуации, а затем заранее решать, какую из них вызывать.
Затем, конечно же, оборудование и ОС имеют многоуровневые кеши, кэш-память микросхемы, кэш SRAM, кэш DRAM, обычный рабочий набор RAM и резервное хранилище на диске. Ваши данные могут дублироваться на каждом уровне кеша. Вся эта сложность означает, что вы можете лишь очень приблизительно предсказать потребление оперативной памяти.
Вы можете использовать Instrumentation.getObjectSize()
, чтобы получить оценку объема памяти, используемого объектом.
Чтобы визуализировать фактический макет объекта, посадочное место и ссылки, вы можете использовать инструмент JOL (Java Object Layout).
В современном 64-битном JDK объект имеет 12-байтовый заголовок, дополненный кратным 8 байтам, поэтому минимальный размер объекта составляет 16 байтов. Для 32-битных JVM накладные расходы составляют 8 байтов с дополнениями, кратными 4 байтам. (Из ответа Дмитрия Спихальского, ответ Джейена и JavaWorld.) < / em>
Обычно ссылки занимают 4 байта на 32-битных платформах или на 64-битных платформах до -Xmx32G
; и 8 байтов больше 32 ГБ (-Xmx32G
). (См. ссылки на сжатые объекты.)
В результате 64-битной JVM обычно требуется на 30-50% больше места в куче. (Что мне следует использовать: 32- или 64-разрядную JVM?, 2012, JDK 1.7)
Упакованные обертки имеют накладные расходы по сравнению с примитивными типами (из JavaWorld):
Integer
: результат в 16 байт немного хуже, чем я ожидал, потому что значениеint
может уместиться всего в 4 дополнительных байта. ИспользованиеInteger
стоит мне 300% накладных расходов на память по сравнению с тем, когда я могу сохранить значение как примитивный тип.
Long
: также 16 байт: очевидно, что фактический размер объекта в куче зависит от низкоуровневого выравнивания памяти, выполняемого конкретной реализацией JVM для определенного типа ЦП. Похоже, чтоLong
- это 8 байтов служебных данных объекта плюс еще 8 байтов для фактического длинного значения. Напротив,Integer
имеет неиспользуемое 4-байтовое отверстие, скорее всего, потому, что JVM, который я использую, принудительно выравнивает объект по 8-байтовой границе слова.
Дорого стоят и другие контейнеры:
Многомерные массивы: это еще один сюрприз.
Разработчики обычно используют такие конструкции, какint[dim1][dim2]
, в числовых и научных вычислениях.В экземпляре массива
int[dim1][dim2]
каждый вложенный массивint[dim2]
является самостоятельнымObject
. Каждый добавляет обычные 16-байтовые накладные расходы на массив. Когда мне не нужен треугольный или рваный массив, это означает чистые накладные расходы. Влияние возрастает, когда размеры массивов сильно различаются.Например, экземпляр
int[128][2]
занимает 3600 байт. По сравнению с 1040 байтами, которые используетint[256]
экземпляр (имеющий такую же емкость), 3600 байтов представляют собой 246-процентные накладные расходы. В крайнем случаеbyte[256][1]
коэффициент накладных расходов почти 19! Сравните это с ситуацией C / C ++, в которой тот же синтаксис не увеличивает накладные расходы на хранилище.
String
: рост памятиString
отслеживает рост его внутреннего массива char. Однако классString
добавляет еще 24 байта служебных данных.Для непустого
String
размером 10 или менее символов добавленные накладные расходы относительно полезной нагрузки (2 байта на каждый символ плюс 4 байта на длину) колеблются от 100 до 400 процентов.
Рассмотрим это пример объекта:
class X { // 8 bytes for reference to the class definition
int a; // 4 bytes
byte b; // 1 byte
Integer c = new Integer(); // 4 bytes for a reference
}
Наивная сумма предполагает, что экземпляр X
будет использовать 17 байтов. Однако из-за выравнивания (также называемого заполнением) JVM выделяет память в количестве, кратном 8 байтам, поэтому вместо 17 байтов она будет выделять 24 байта.
Это зависит от архитектуры / jdk. Для современной архитектуры JDK и 64-битной архитектуры объект имеет 12-байтовый заголовок и заполнение на 8 байтов, поэтому минимальный размер объекта составляет 16 байтов. Вы можете использовать инструмент под названием Java Object Layout, чтобы определить размер и получить подробную информацию. о макете объекта и внутренней структуре любого объекта или угадайте эту информацию по ссылке на класс. Пример вывода для Integer в моей среде:
Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
java.lang.Integer object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 12 (object header) N/A
12 4 int Integer.value N/A
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
Итак, для Integer размер экземпляра составляет 16 байтов, потому что 4-байтовые int сжимаются на месте сразу после заголовка и перед границей заполнения.
Пример кода:
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.util.VMSupport;
public static void main(String[] args) {
System.out.println(VMSupport.vmDetails());
System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
}
Если вы используете maven, чтобы получить JOL:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.3.2</version>
</dependency>
У каждого объекта есть определенные накладные расходы на связанный с ним монитор и информацию о типе, а также на сами поля. Помимо этого, поля могут быть размещены практически так, как JVM считает нужным (я считаю), но как показано в другом ответе, по крайней мере, некоторые JVM будут упакованы довольно плотно. Рассмотрим такой класс:
public class SingleByte
{
private byte b;
}
vs
public class OneHundredBytes
{
private byte b00, b01, ..., b99;
}
На 32-битной JVM я бы ожидал, что 100 экземпляров SingleByte
займут 1200 байтов (8 байтов служебных + 4 байта для поля из-за заполнения / выравнивания). Я ожидаю, что один экземпляр OneHundredBytes
займет 108 байтов - служебные данные, а затем 100 байтов, упакованных. Это, безусловно, может варьироваться в зависимости от JVM - одна реализация может решить не упаковывать поля в OneHundredBytes
, что приведет к тому, что она займет 408 байтов (= 8 байтов накладных расходов + 4 * 100 выровненных / дополненных байтов). На 64-битной JVM накладные расходы тоже могут быть больше (не уверен).
РЕДАКТИРОВАТЬ: см. Комментарий ниже; очевидно, HotSpot ограничивает границы 8 байтами вместо 32, поэтому каждый экземпляр SingleByte
будет занимать 16 байтов.
В любом случае «один большой объект» будет по крайней мере так же эффективен, как несколько небольших объектов - для таких простых случаев, как этот.
Похоже, что каждый объект имеет накладные расходы в 16 байт в 32-битных системах (и 24 байта в 64-битных системах).
http://algs4.cs.princeton.edu/14analysis/ - хороший источник информации. . Среди множества хороших примеров можно привести следующий.
http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf также очень информативен, например:
Является ли пространство памяти, используемое одним объектом со 100 атрибутами, таким же, как у 100 объектов, каждый с одним атрибутом?
No.
Сколько памяти отведено под объект?
Сколько дополнительного места используется при добавлении атрибута?
Общий объем используемой / свободной памяти программы можно получить в программе через
java.lang.Runtime.getRuntime();
Среда выполнения имеет несколько методов, связанных с памятью. Следующий пример кодирования демонстрирует его использование.
public class PerformanceTest {
private static final long MEGABYTE = 1024L * 1024L;
public static long bytesToMegabytes(long bytes) {
return bytes / MEGABYTE;
}
public static void main(String[] args) {
// I assume you will know how to create an object Person yourself...
List <Person> list = new ArrayList <Person> ();
for (int i = 0; i <= 100_000; i++) {
list.add(new Person("Jim", "Knopf"));
}
// Get the Java runtime
Runtime runtime = Runtime.getRuntime();
// Run the garbage collector
runtime.gc();
// Calculate the used memory
long memory = runtime.totalMemory() - runtime.freeMemory();
System.out.println("Used memory is bytes: " + memory);
System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
}
}
Нет, для регистрации объекта тоже требуется немного памяти. 100 объектов с 1 атрибутом займут больше памяти.
Вопрос будет очень широким.
Это зависит от переменной класса, или вы можете вызвать использование памяти в java.
Он также требует дополнительной памяти для заголовков и ссылок.
Память кучи, используемая объектом Java, включает
память для примитивных полей в соответствии с их размером (размеры примитивных типов см. ниже);
память для справочных полей (по 4 байта);
заголовок объекта, состоящий из нескольких байтов «служебной» информации;
Для объектов в java также требуется некоторая «служебная» информация, такая как запись класса объекта, идентификатора и флагов состояния, например, доступен ли объект в данный момент, заблокирован ли в данный момент синхронизация и т. Д.
Размер заголовка объекта Java варьируется на 32- и 64-битных jvm.
Хотя это основные потребители памяти, jvm также иногда требует дополнительных полей, например, для выравнивания кода и т. Д.
Размеры примитивных типов
логическое и байтовое - 1
char & short - 2
int & float - 4
длинное и двойное - 8
Я получил очень хорошие результаты от java .lang.instrument.Instrumentation, упомянутый в другом ответе. Хорошие примеры его использования см. В статье Счетчик памяти прибора < / em> из информационного бюллетеня специалистов по Java и библиотеки java.sizeOf на SourceForge.
Если это кому-то будет полезно, вы можете загрузить с моего веб-сайта небольшой Java-агент для запроса использования памяти объект. Это также позволит вам запрашивать "глубокое" использование памяти.
(String, Integer)
Guava Cache для каждого элемента. Спасибо!
- person Steve K; 03.11.2015
нет, 100 маленьких объектов требует больше информации (памяти), чем один большой.
Правила использования памяти зависят от реализации JVM и архитектуры ЦП (например, 32-разрядная версия вместо 64-разрядной).
Подробные правила для SUN JVM см. В моем старом блог
С уважением, Маркус