[JVM Series 4] Сколько байтов занимает новый Object()?После прочтения я полностью это пойму

Java

предисловие

Предыдущий Мы проанализировалиПроцесс выполнения метода виртуальной машины Java, перегрузка методов и принципы перезаписи методов, и проанализировали процесс вызова и принцип метода. Стек виртуальной машины Java является закрытым для потоков и не имеет проблем с безопасностью данных. По сравнению со стеком виртуальной машины Java, куча более сложна, поскольку куча представляет собой пространство памяти, совместно используемое все потоки. , будут проблемы с безопасностью потоков, а сборка мусора в основном предназначена для освобождения места в куче, поэтому нам очень необходимо понимать расположение в куче. Теперь продолжим анализ размещения кучи и размещения объектов Java в памяти.

объект, указывающий

Давайте сначала посмотрим на кусок кода:

package com.zwx.jvm;

public class HeapMemory {
    private Object obj1 = new Object();

    public static void main(String[] args) {
        Object obj2 = new Object();
    }
}

В приведенном выше коде в чем разница между obj1 и obj2 в памяти?

Давайте вспомнимJVM серия 1Как упоминалось в статье, в области методов хранится структура каждого класса, например: пул констант времени выполнения, данные свойств и методов, а также такие данные, как методы и конструкторы. Итак, наш obj1 существует в области методов, а new создаст экземпляр объекта, а экземпляр объекта хранится в куче, так что у нас есть следующая картина (Область метода указывает на кучу):
在这里插入图片描述
А obj2 — это локальная переменная в методе, которая хранится в таблице локальных переменных во фрейме стека в стеке виртуальной машины Java, это классикастек указывает на кучу:
在这里插入图片描述
Здесь давайте подумаем еще раз.Одна из наших переменных указывает на кучу, а куча хранит только объект экземпляра.Так как же пример объекта в куче знает, к какому классу он принадлежит, то есть как экземпляр знает класс, которому он соответствует?А как насчет метаинформации? Это включает в себя то, как объект Java размещается в памяти.

Модель памяти Java

Память объекта можно разделить на три области: заголовок объекта (Header), данные экземпляра (Instance Data) и заполнение выравнивания (Padding),В качестве примера возьмем 64-битную операционную систему (случай, когда сжатие указателя не включено)Схема объекта Java показана на следующем рисунке:
在这里插入图片描述
Подробности в Mark Word в шапке объекта есть в статьеПринцип синхронного обновления замкаподробно описаны.
Заполнение выравнивания на приведенном выше рисунке не обязательно требуется.Если сумма заголовка объекта и данных экземпляра кратна 8 байтам, то заполнение выравнивания не требуется.

Зная схему памяти Java, давайте рассмотрим вопрос интервью

Object obj=new Object() занимает байты

Это вопрос, который упоминают многие люди в Интернете. Затем, в сочетании с приведенным выше расположением памяти Java, давайте проанализируем. Взяв в качестве примера 64-битную операционную систему, размер new Object() делится на два случая:

  • Сжатие указателя не включено
    Занимаемый размер:8(знак слова)+8(указатель класса)=16 байт
  • Сжатие указателя включено (по умолчанию включено)
    После включения сжатия указателя указатель класса будет сжат до 4 байтов, а окончательный размер будет следующим:
    8(знак слова)+4(указатель класса)+4(заполнение выравнивания)=16 байт

Это результат? Давайте проверим.
Сначала введите зависимость pom:

<dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.10</version>
        </dependency>

Затем создайте простую демонстрацию:

package com.zwx.jvm;

import org.openjdk.jol.info.ClassLayout;

public class HeapMemory {
    public static void main(String[] args) {
        Object obj = new Object();
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());
    }
}

Результат выглядит следующим образом:
在这里插入图片描述
Итоговый результат 16 байт, проблем нет, это потому, что сжатие указателя включено по умолчанию, тогда будем пробовать после отключения сжатия указателя.

-XX:+UseCompressedOops  开启指针压缩
-XX:-UseCompressedOops  关闭指针压缩

在这里插入图片描述
Запустите его снова и получите следующие результаты:
在这里插入图片描述
Видно, что в это время нет заполнения выравнивания, но занимаемый размер по-прежнему составляет 16 бит.

Далее давайте продемонстрируем размер объекта с атрибутами.

Создайте новый класс только с одним байтовым свойством внутри:

package com.zwx.jvm;

public class MyItem {
    byte i = 0;
}

Затем выведите размер этого класса в сценариях с включенным сжатием указателя и выключенным сжатием указателя.

package com.zwx.jvm;

import org.openjdk.jol.info.ClassLayout;

public class HeapMemory {
    public static void main(String[] args) {
        MyItem myItem = new MyItem();
        System.out.println(ClassLayout.parseInstance(myItem).toPrintable());
    }
}

Включите сжатие указателя, занимающего 16 байт:
在这里插入图片描述
Отключить сжатие указателя, занимающего 24 байта:
在这里插入图片描述
В настоящее время можно увидеть, что преимущества сжатия указателей включены.Если постоянно создается большое количество объектов, сжатие указателей все же может в определенной степени оптимизировать производительность.

доступ к объекту

После создания объекта нам, конечно же, нужно получить к нему доступ, поэтому, когда нам нужно получить доступ к объекту, как мы находим этот объект?
Существует два основных способа доступа к объектам:обрабатывать доступипрямой доступ по указателю.

  • обрабатывать доступ
    Если используется доступ к дескриптору, виртуальная машина Java делит часть памяти в куче для хранения пула дескрипторов, затем адрес дескриптора сохраняется в объекте, а затем в дескрипторе сохраняются данные экземпляра объекта и адрес данных типа объекта. бассейн.
    在这里插入图片描述
  • Прямой доступ по указателю (как использует виртуальная машина Hot Spot)
    При доступе к прямому указателю данные типа объекта будут храниться непосредственно в объекте.
    在这里插入图片描述

Управление доступом и сравнение прямого доступа к указателю

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

куча памяти

Выше мы упомянули, что Mark Word в заголовке объекта Java хранит возраст поколения объекта, так что же такое возраст поколения?

Возраст генерации объекта можно понимать как количество сборок мусора.Когда объект все еще существует после одной сборки мусора, возраст генерации увеличивается на 1. В 64-битной виртуальной машине возраст генерации составляет 4 бита, наибольшее значение равно 15. Возраст генерации по умолчанию равен 0000, и он будет постепенно увеличиваться с увеличением количества сборок мусора.

Память кучи Java разделена в соответствии с возрастом поколения, которое делится на область Young и область Old.Распределение объектов сначала будет идти в область Young, а по достижении определенного возраста поколения (-XX:MaxTenuringThreshold можно установить размер, по умолчанию 15), он войдет в старую область.(Примечание. Если объект слишком большой, он сразу перейдет в старую область.).

Причина такого разделения заключается в том, что если во всей куче есть только одна область, то все объекты в куче необходимо сканировать каждый раз во время сборки мусора, что снижает производительность. На самом деле жизненный цикл большинства Java-объектов очень короткий.Если объект не может быть повторно использован много раз, можно считать, что он не может быть повторно использован при следующей сборке мусора.Поэтому сборка мусора в области Юнга и Старая область может быть отдельно, только когда в молодой области еще не осталось места после сборки мусора, тогда инициировать сборку мусора в старой области.
在这里插入图片描述

Молодой район

Теперь она разбита на область Young, затем давайте посмотрим на следующую сцену.Следующая Young представляет собой обзор после сборки мусора:
在这里插入图片描述
Если сейчас есть объект, он будет занимать размер 2 объектов, и вы обнаружите, что не можете его вставить. В это время будет запущен GC (сборка мусора), но как только GC (сборка мусора) будет срабатывает, оно повлияет на пользовательские потоки. Да, потому что в процессе GC, чтобы гарантировать, что ссылка на объект не будет постоянно изменяться, все пользовательские потоки должны быть остановлены. Sun называет это событие: Stop the World (STW ). Они будут подробно представлены в следующей статье, посвященной сборке мусора, поэтому я не буду здесь углубляться.

В общем, чем меньше GC, тем лучше, но на самом деле вы можете видеть на рисунке выше, что можно положить как минимум 3 объекта, пока объекты расположены по порядку, их можно поставить вниз, так что это приводит к проблеме,Очевидно, что место есть, но поскольку пространство не является непрерывным, объекту не удается применить память, что приводит к срабатыванию сборщика мусора., так как решить эту проблему?

Решение состоит в том, чтобы расположить объекты в области Юнга по порядку, поэтому был создан метод, чтобы снова разделить область Юнга на две области:Эдемский райониОбласть выжившего.
在这里插入图片描述
Конкретная операция: после прибытия объекта он сначала размещается в области Эдема.После заполнения области Эдема запускается GC.После GC, чтобы предотвратить разрыв пространства, уцелевшие объекты копируются в область Выживших, а затем область Эдема можно Полностью зачистить, конечно, для этого есть предпосылка,То есть у большинства объектов очень короткий жизненный цикл, в принципе, большинство объектов в районе Эдема можно переработать одной сборкой мусора.(Эта предпосылка получена путем тестирования и обобщения).

При срабатывании ГК область Выжившего также будет перерабатываться вместе.Это не значит, что только область Эдема срабатывает одна, но эта проблема возникает снова.Область Эдема гарантирует, что пространство в основном непрерывное, но область Выжившего может генерировать фрагменты пространства, что приводит к разрыву, поэтому мы разделили область Survivor на две части:
在这里插入图片描述
На этот раз рабочий процесс выглядит следующим образом:
Сначала выделяем место в области Эдема, после заполнения области Эдема запускаем GC, после GC копируем уцелевшие объекты в область S0 (область S1 пуста), а затем продолжаем выделять объекты в области Eden После повторного срабатывания GC, если вы обнаружите, что область S0 сохранена Если места больше нет (космический мусор есть, на самом деле есть место), то скопируйте объекты в области S0 в область S1, и скопируйте выжившие объекты в область S1.В это время область S0 пуста, и повторите операцию по очереди.Если мы скажем После того, как космический объект в области S0 или области S1 скопирован и перемещен, его все еще нельзя поставить вниз , что означает, что в это время он действительно заполнен, поэтому идите в зону для пожилых людей, чтобы занять немного места (этоГарантийный механизм, старость должна предоставить эту гарантию распределения пространства), если места в старой области недостаточно, он вызовет полный сборщик мусора, если его все еще недостаточно, он выдаст исключение OutOfMemeoyError.

Примечание. Для обеспечения плавного выполнения каждой копии между двумя областями S0 и S1 размеры двух областей S0 и S1 должны быть одинаковыми, а одна область должна быть одновременно пустой. Хотя такой подход приведет к небольшой трате места, стоит объединить другие улучшения производительности.

Старый район

Когда объект в молодой области достигнет установленного возраста генерации, объект войдет в старую область.После того, как старая область будет заполнена, будет запущен полный GC.Если пространство не может быть очищено, будет выдано исключение OutOfMemeoyError.

грамотность

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

  • Сборка мусора: сокращенно GC.
  • Minor GC: GC для нового поколения
  • Major GC: для GC старого возраста, когда GC срабатывает в старом возрасте, также срабатывает Minor GC, что эквивалентно срабатыванию Full GC.
  • Полный GC: GC происходит одновременно в новом поколении + старом поколении.
  • Молодой район: Новое поколение
  • Старый район: старость
  • Eden District: я пока не нашел ни одного китайского перевода (Eden Garden?)
  • Зона выжившего: Зона выжившего
  • S0 и S1: также известны как области "от" и "куда". Обратите внимание, что области "от" и "куда" постоянно обмениваются идентификаторами, а S0 и S1 должны быть равны, и убедитесь, что область пуста.

Жизненная траектория объекта

Из приведенного выше введения у вас должно сложиться общее впечатление, что объект будет продолжать циркулировать в районе Эдема, районе S0, районе S1 и районе Старого (конечно, за исключением недолговечных объектов, которые будут переработаны в начале). ), мы можем получить следующую блок-схему:
在这里插入图片描述

Суммировать

В этой статье в основном рассказывается о том, как объект Java хранится в куче, и комбинируется структура памяти объектов Java, чтобы продемонстрировать размер общего объекта, а затем анализируется разделение пространства в куче и причины разделения. Проблемы, связанные с сборщиком мусора Знания не объясняются подробно.Соответствующие знания о сборщике мусора, алгоритме сборки мусора и сборщике мусора будут подробно проанализированы в следующей статье.

**Пожалуйста, следуйте за мной, учитесь и развивайтесь вместе**

Серия статей JVM постоянно обновляется