Как рассчитать объем памяти массива Java? - PullRequest
0 голосов
/ 24 мая 2018

Я знаю, как рассчитать объем памяти объекта Java, добавив три части: заголовок + свойства + ссылка.

Я также знаю, что массив Java тоже является объектом.

Но когдаЯ прочитал «Понимание расширенных возможностей и рекомендаций JVM, второе издание», там говорится, что заголовок массива Java состоит из трех частей;пометить слово, указатель класса и длину массива.

В 64-битной JVM Hotspot всегда будет 24 байта.

Но в 32-битной JVM как вычислить память массива Javasize?

Я надеюсь, что вы, ребята, можете дать мне пример Java-кода, который покажет мне, как вычислять объем памяти объекта, не ограниченный массивом объекта.

Ответы [ 2 ]

0 голосов
/ 24 мая 2018

Фактический размер объекта зависит от реализации, и даже не требуется, чтобы необходимый размер объекта оставался неизменным в течение всего срока его жизни.

На wiki.openjdk.java есть статья.net заявив:

Расположение заголовка объекта

Заголовок объекта состоит из слова метки собственного размера, слова класса, слова длиной 32 бита (если объектявляется массивом), 32-разрядный пробел (если требуется правилами выравнивания), а затем ноль или более полей экземпляров, элементов массива или полей метаданных.(Интересные мелочи: метаобъекты Klass содержат таблицу V ++ сразу после слова klass.)

Поле пробела, если оно существует, часто доступно для хранения полей экземпляра.

Если UseCompressedOops имеет значение false (и всегда в системах ILP32), знак и класс являются родными машинными словами.Для массивов разрыв всегда присутствует в системах LP64 и только в массивах с 64-битными элементами в системах ILP32.

Если UseCompressedOops имеет значение true, класс равен 32 битам.Номера для массивов имеют поле пропуска сразу после класса, в то время как массивы сохраняют поле длины сразу после класса.

Вы вычисляете «заголовок + свойства + ссылка» для размера объекта неверно.Во-первых, ссылки на объект не являются частью размера объекта референта.Может быть произвольное количество ссылок на один и тот же объект, но эти ссылки вообще не должны быть в памяти кучи или в ОЗУ, поскольку оптимизированный код может обращаться к объекту исключительно через регистры ЦП.

Кроме того, как указывалось в приведенной выше цитате, существуют правила выравнивания, которые делают вычисление памяти, требуемой для полей, нетривиальным.В заголовке может быть пробел, который можно использовать для хранения полей экземпляра, если в него входят поля типа, подходящего для него.Хотя поля одного и того же класса могут быть расположены так, чтобы минимизировать заполнение, подкласс должен соответствовать макету суперкласса, потенциально добавляя к нему больше полей, и может заполнять пробелы только в том случае, если у него есть поля подходящих типов, в противном случаеможет быть еще больше пробелов из-за иерархии классов.

Для массивов вы можете извлечь из процитированной статьи, что 32-битное представление HotSpot использует заголовок из 12 байтов, если тип не равен long[] или * 1024.*, в этом случае это будет 16 байтов.

Для 64-битной реализации опция UseCompressedOops (которая включена по умолчанию) позволяет комбинировать слово 64-битной метки с 32-битным классом иДлина 32 бита, до заголовка 16 байтов.Только если UseCompressedOops выключен, заголовок будет 24 байта.

0 голосов
/ 24 мая 2018

Вы можете проверить это с помощью JOL framework , написанного всемогущим Алексеем Шипилевым.

Использовать его на самом деле довольно просто, сначала давайте определим макеты, которые вам интересны:

Layouter layout32Bits =  new HotSpotLayouter(new X86_32_DataModel());
Layouter layout64Bits = new HotSpotLayouter(new X86_64_DataModel());
Layouter layout64BitsComp = new HotSpotLayouter(new X86_64_COOPS_DataModel());

А затем давайте определим массив и посмотрим результаты:

int [] ints = new int[1];
System.out.println(ClassLayout.parseInstance(ints, layout32Bits).toPrintable());
System.out.println(ClassLayout.parseInstance(ints, layout64Bits).toPrintable());
System.out.println(ClassLayout.parseInstance(ints, layout64BitsComp).toPrintable());

Давайте запустим каждый из них по очереди.Для 32bits VM:

  [I object internals:
  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
  0     4        (object header)                           09 00 00 00 (00001001 00000000 00000000 00000000) (9)
  4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
  8     4        (object header)                           10 0b 40 29 (00010000 00001011 01000000 00101001) (692062992)
 12    40    int [I.<elements>                             N/A
 52    12        (loss due to the next object alignment)
 Instance size: 64 bytes
 Space losses: 0 bytes internal + 12 bytes external = 12 bytes total

Итак, вы получаете 12 bytes для заголовков, (4 + 4 для двух заголовков, плюс 4 для размера массива, это int);затем вы получите 40 байт за 10 дюймов, которые будет содержать массив.

Далее я не совсем уверен, что понимаю.Пока у нас есть 52 байтов, и объекты выровнены по 8 bytes, что означает, что это значение 52 должно быть округлено до 56 bytes, чтобы выровнять его до 8.

Вместо этого написано 12 bytes loss due to the next object alignment.Я могу только предположить, что потенциально могут быть две вещи, сначала прочитайте комментарии здесь или , может быть, какое-то поле есть только для внутреннего использования .

Не собираюсь показыватьостальные примеры выводятся здесь (вы тоже можете это сделать), и я задам дополнительный вопрос о том, что мне не совсем понятно в отношении заполнения в ближайшее время.

...