Какое потребление памяти у объекта в Java?

Является ли пространство памяти, используемое одним объектом со 100 атрибутами, таким же, как у 100 объектов, каждый с одним атрибутом?

Сколько памяти отведено под объект?
Сколько дополнительного места используется при добавлении атрибута?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
220
0
119 559
12

Ответы 12

Нет, для регистрации объекта тоже требуется немного памяти. 100 объектов с 1 атрибутом займут больше памяти.

нет, 100 маленьких объектов требует больше информации (памяти), чем один большой.

У каждого объекта есть определенные накладные расходы на связанный с ним монитор и информацию о типе, а также на сами поля. Помимо этого, поля могут быть размещены практически так, как JVM считает нужным (я считаю), но, поскольку показано в другом ответе, по крайней мере, немного JVM будут упакованы довольно плотно. Рассмотрим такой класс:

public class SingleByte
{
    private byte b;
}

против

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 байтов.

В любом случае «один большой объект» будет по крайней мере так же эффективен, как несколько небольших объектов - для таких простых случаев, как этот.

Фактически, один экземпляр SingleByte займет 16 байтов на Sun JVM, то есть 8 байтов служебных данных, 4 байта для поля и затем 4 байта для заполнения объекта, поскольку компилятор HotSpot округляет все до кратных 8.

Paul Wagland 24.01.2011 04:26

Mindprod указывает, что на этот вопрос непросто ответить:

A JVM is free to store data any way it pleases internally, big or little endian, with any amount of padding or overhead, though primitives must behave as if they had the official sizes.
For example, the JVM or native compiler might decide to store a boolean[] in 64-bit long chunks like a BitSet. It does not have to tell you, so long as the program gives the same answers.

  • It might allocate some temporary Objects on the stack.
  • It may optimize some variables or method calls totally out of existence replacing them with constants.
  • It might version methods or loops, i.e. compile two versions of a method, each optimized for a certain situation, then decide up front which one to call.

Then of course the hardware and OS have multilayer caches, on chip-cache, SRAM cache, DRAM cache, ordinary RAM working set and backing store on disk. Your data may be duplicated at every cache level. All this complexity means you can only very roughly predict RAM consumption.

Методы измерения

Вы можете использовать Instrumentation.getObjectSize(), чтобы получить оценку хранилища, потребляемого объектом.

Для визуализации компоновки, посадочного места и ссылок объекта действительный можно использовать Инструмент JOL (Java Object Layout).

Заголовки объектов и ссылки на объекты

В современном 64-битном JDK объект имеет 12-байтовый заголовок, дополненный кратным 8 байтам, поэтому минимальный размер объекта составляет 16 байтов. Для 32-битных JVM накладные расходы составляют 8 байтов с дополнениями, кратными 4 байтам. (Из Ответ Дмитрия Спихальского, Ответ Джейен и JavaWorld.)

Обычно ссылки составляют 4 байта на 32-битных платформах или на 64-битных платформах вплоть до -Xmx32G; и 8 байтов выше 32 ГБ (-Xmx32G). (См. ссылки на сжатые объекты.)

В результате 64-битной JVM обычно требуется на 30-50% больше места в куче. (Что мне следует использовать: 32- или 64-битную JVM?, 2012, JDK 1.7)

Упакованные типы, массивы и строки

Упакованные обертки имеют накладные расходы по сравнению с примитивными типами (из JavaWorld):

  • Integer: The 16-byte result is a little worse than I expected because an int value can fit into just 4 extra bytes. Using an Integer costs me a 300 percent memory overhead compared to when I can store the value as a primitive type

  • Long: 16 bytes also: Clearly, actual object size on the heap is subject to low-level memory alignment done by a particular JVM implementation for a particular CPU type. It looks like a Long is 8 bytes of Object overhead, plus 8 bytes more for the actual long value. In contrast, Integer had an unused 4-byte hole, most likely because the JVM I use forces object alignment on an 8-byte word boundary.

Дорого стоят и другие контейнеры:

  • Multidimensional arrays: it offers another surprise.
    Developers commonly employ constructs like int[dim1][dim2] in numerical and scientific computing.

    In an int[dim1][dim2] array instance, every nested int[dim2] array is an Object in its own right. Each adds the usual 16-byte array overhead. When I don't need a triangular or ragged array, that represents pure overhead. The impact grows when array dimensions greatly differ.

    For example, a int[128][2] instance takes 3,600 bytes. Compared to the 1,040 bytes an int[256] instance uses (which has the same capacity), 3,600 bytes represent a 246 percent overhead. In the extreme case of byte[256][1], the overhead factor is almost 19! Compare that to the C/C++ situation in which the same syntax does not add any storage overhead.

  • String: a String's memory growth tracks its internal char array's growth. However, the String class adds another 24 bytes of overhead.

    For a nonempty String of size 10 characters or less, the added overhead cost relative to useful payload (2 bytes for each char plus 4 bytes for the length), ranges from 100 to 400 percent.

Выравнивание

Рассмотрим этот пример объекта:

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 байта.

int [128] [6]: 128 массивов из 6 целых чисел - всего 768 байтов, 3072 байта данных + 2064 байта Накладные расходы на объект = всего 5166 байтов. int [256]: всего 256 int - поэтому несопоставимо. int [768]: 3072 байта данных + 16 байтов накладных расходов - примерно 3/5 пространства 2D-массива - не совсем 246% накладных расходов!

JeeBee 07.04.2009 20:07

Ах, в исходной статье использовалось int [128] [2], а не int [128] [6] - интересно, как это изменилось. Также показывает, что крайние примеры могут рассказать другую историю.

JeeBee 07.04.2009 20:09

@Jeebee: я исправил опечатки. int [128] [2] стал int [128] [6] из-за ошибки в редакторе Javascript: ссылки указываются с помощью [aTest] [x], и редактор принял [128] [2] как адрес ссылки ! Он «переупорядочил» индексы этих ссылок, изменив [2] на [6] ... сложно!

VonC 07.04.2009 21:02

Накладные расходы составляют 16 байт в 64-битной JVM.

Tim Cooper 12.04.2013 17:00

@TimCooper Нет! Накладные расходы (= new Object ()) 64-битной Sun VM Java 1.6, работающей на 64-битной Win7, Intel составляют 12 байтов + 4 отступа до следующего числа, кратного 8, составляют 16 байтов. Итак, если у вас есть объект с одним полем int, это все равно 16 байтов. (без отступов)

AlexWien 17.07.2014 19:06

@AlexWien: Некоторые схемы сборки мусора могут устанавливать минимальный размер объекта, отдельный от заполнения. Во время сборки мусора, как только объект копируется из старого местоположения в новое, старое местоположение может больше не хранить данные для объекта, но оно должно будет содержать ссылку на новое местоположение; может также потребоваться сохранить ссылку на старое местоположение объекта, в котором была обнаружена первая ссылка, и смещение этой ссылки в старом объекте [поскольку старый объект может все еще содержать ссылки, которые еще не были обработаны].

supercat 19.09.2014 20:34

@AlexWien: использование памяти в старом местоположении объекта для хранения бухгалтерской информации сборщика мусора позволяет избежать необходимости выделять для этой цели другую память, но может потребовать минимального размера объекта, который больше, чем требовалось бы в противном случае. Я думаю, что по крайней мере одна версия сборщика мусора .NET использует этот подход; Конечно, некоторые сборщики мусора Java тоже могли бы поступить так же.

supercat 19.09.2014 20:38

@VonC Этот ответ устарел, потому что в наши дни многие люди используют 64-битные JVM, и ваш ответ фактически игнорирует 64-битные JVM. Хорошо сказать «ну, это зависит от ...», но также полезно дать несколько хороших практических советов - вещей, которые верны для 99% JVM, таких как «8 байтов для 32-битных, 12 байтов + 8-байтовое выравнивание. для 64 бит, плюс указатели на 8 байт выше -Xmx32G ".

Tim Cooper 15.02.2016 13:43

Я получил очень хорошие результаты от подхода java.lang.instrument.Instrumentation, упомянутого в другом ответе. Хорошие примеры его использования см. В статье Счетчик памяти КИП из Информационного бюллетеня JavaSpecialists и библиотеки java.sizeOf на SourceForge.

Правила о том, сколько памяти потребляется, зависят от реализации JVM и архитектуры ЦП (например, 32-разрядная версия вместо 64-разрядной).

Чтобы узнать подробные правила для SUN JVM, проверьте мой старый блог

С уважением, Маркус

Я почти уверен, что Sun Java 1.6 64bit, нужно 12 байтов для простого объекта + 4 отступа = 16; Объект + одно целочисленное поле = 12 + 4 = 16

AlexWien 16.07.2014 23:18

Вы закрыли свой блог?

Johan Boulé 02.02.2020 05:26

Не совсем. Не уверен, что блоги SAP каким-то образом переместились. Большинство из них можно найти здесь kohlerm.blogspot.com

kohlerm 08.02.2020 18:19

Если это кому-то будет полезно, вы можете скачать с моего сайта небольшой Агент Java для запроса использования памяти объектом. Это также позволит вам запрашивать "глубокое" использование памяти.

Это отлично сработало для получения приблизительной оценки того, сколько памяти использует (String, Integer) Guava Cache для каждого элемента. Спасибо!

Steve K 03.11.2015 21:54

Общий объем используемой / свободной памяти программы можно получить в программе через

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));
     }
 }

Вопрос будет очень широким.

Это зависит от переменной класса, или вы можете вызвать использование памяти в java.

Он также требует дополнительной памяти для заголовков и ссылок.

Память кучи, используемая объектом Java, включает

  • память для примитивных полей в соответствии с их размером (размеры примитивных типов см. ниже);

  • память для справочных полей (по 4 байта);

  • заголовок объекта, состоящий из нескольких байтов «служебной» информации;

Для объектов в java также требуется некоторая "служебная" информация, такая как запись класса объекта, идентификатора и флагов состояния, например, доступен ли объект в данный момент, заблокирован ли в данный момент синхронизация и т. д.

Размер заголовка объекта Java варьируется на 32- и 64-битных jvm.

Хотя это основные потребители памяти, jvm также иногда требует дополнительных полей, например, для выравнивания кода и т. д.

Размеры примитивных типов

логическое и байтовое - 1

char & short - 2

int & float - 4

длинный и двойной - 8

Читатели также могут найти этот документ очень поучительным: cs.virginia.edu/kim/publicity/pldi09tutorials/…

quellish 16.01.2014 05:54

Похоже, что каждый объект имеет накладные расходы в 16 байт в 32-битных системах (и 24 байта в 64-битных системах).

http://algs4.cs.princeton.edu/14analysis/ - хороший источник информации. Среди многих хороших примеров можно привести следующий.

http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf тоже очень информативный, например:

«Похоже, что на каждый объект приходится 16 байтов в 32-битных системах (и 24 байта в 64-битных системах)». Это неправильно, по крайней мере, для текущих JDK. Взгляните на мой пример отвечать для целого числа. Накладные расходы объекта составляют не менее 12 байт для заголовка для 64-битной системы и современного JDK. Может быть больше из-за заполнения, зависит от фактического расположения полей в объекте.

Dmitry Spikhalskiy 07.09.2015 01:59

Вторая ссылка на учебник по Java с эффективным использованием памяти кажется мертвой - я получаю «Запрещено».

tsleyson 08.08.2017 01:09

Это зависит от архитектуры / jdk. Для современной архитектуры JDK и 64-битной архитектуры объект имеет 12-байтовый заголовок и заполнение на 8 байтов, поэтому минимальный размер объекта составляет 16 байтов. Вы можете использовать инструмент под названием Макет объекта Java, чтобы определить размер и получить подробную информацию о макете объекта и внутренней структуре любого объекта или угадать эту информацию по ссылке на класс. Пример вывода для 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>

Is the memory space consumed by one object with 100 attributes the same as that of 100 objects, with one attribute each?

Нет.

How much memory is allocated for an object?

  • Накладные расходы составляют 8 байтов для 32-разрядной версии, 12 байтов для 64-разрядной версии; а затем округляется до кратного 4 байтам (32-разрядная версия) или 8 байтов (64-разрядная версия).

How much additional space is used when adding an attribute?

  • Атрибуты варьируются от 1 байта (байта) до 8 байтов (длинный / двойной), но ссылки имеют размер 4 байта или 8 байтов в зависимости от нет от того, 32-битный он или 64-битный, а скорее от того, является ли -Xmx <32 ГБ или> = 32 ГБ: обычно 64 -bit JVM имеют оптимизацию, называемую "-UseCompressedOops", которая сжимает ссылки до 4 байтов, если размер кучи меньше 32 ГБ.

char - это 16 бит, а не 8 бит.

comonad 26.06.2019 20:58

вы правы. кто-то, кажется, отредактировал мой исходный ответ

Jayen 27.06.2019 05:19

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