«Серия JVM», глава 6 — создание объектов и структура памяти

Как создаются объекты

  • новый объект: самый распространенный способ User user = new User();.
  • Через отражение: вызовите конструктор для инициализации
    метода newInstance() объекта Class: User user = User.class.newInstance();, поскольку можно вызвать только конструктор нулевого параметра, разрешение должно быть общедоступным.
    Метод конструктора newInstance(Xxx): Constructor<User> constructor = User.class.getInstance(); User user = constructor.newInstance();может вызывать пустые параметры или конструкторы с параметрами .
  • Используйте метод clone() объекта, чтобы вернуть объект: User user2 = <User>user.clone();без вызова какого-либо конструктора скопируйте существующие данные напрямую, чтобы инициализировать вновь созданный объект. Требуется, чтобы текущий класс реализовывал интерфейс клонирования в интерфейсе Cloneable.
  • Используйте метод десериализации: ObjectInputStream in = new ObjectInputStream (new FileInputStream(filename)); User user = (User)obj.readObject();сериализация обычно используется для передачи по сети сокетов .
  • Создавайте объекты через сторонние библиотеки, такие как Objenesis

Шаги для создания объекта

Процесс создания объекта:

  • Загрузить метаинформацию класса и определить, существует ли метаинформация класса (загрузка, связывание, инициализация).
  • Выделить память для объектов
  • Обработка проблем параллелизма
  • Инициализировать выделенное пространство, инициализация свойств по умолчанию (инициализация с нулевым значением)
  • Установить информацию заголовка объекта
  • Выполнение инициализации метода init (инициализация отображения свойств, инициализация в блоках кода, инициализация конструктора)

Загрузка метаинформации о классе: когда
виртуальная машина встречает новую инструкцию, она сначала проверяет, могут ли параметры этой инструкции найти символическую ссылку класса в постоянном пуле метапространства, и проверяет, был ли класс, представленный этой символической ссылкой, загружается, разрешается и инициализируется. Если нет, то в режиме родительского делегирования используйте текущий загрузчик классов, чтобы найти соответствующий файл .class с ClassLoader + имя пакета + ключ имени класса, если файл не найден, сгенерируйте исключение ClassNotFoundException , если найден, выполните класс Загрузите и сгенерируйте соответствующий объект класса.

Выделите память для объектов:
сначала рассчитайте размер пространства, занимаемого объектом, а затем разделите блок памяти в куче для нового объекта. Если переменная-член экземпляра является ссылочной переменной, выделяется только пространство ссылочной переменной, размер которого составляет 4 байта. Метод выделения определяется тем, является ли куча Java регулярной, а регулярность кучи Java определяется тем, имеет ли используемый сборщик мусора функцию сжатия.

  • Если память обычная: виртуальная машина будет использовать метод коллизии указателей (Bump The Point) для выделения памяти под объект.
  • Если память нерегулярна: виртуальная таблица должна поддерживать список для свободного распределения списка .

Метод коллизии указателей:
вся используемая память находится на одной стороне, свободная память — на другой стороне, а указатель помещается посередине как индикатор точки разграничения, выделение памяти — это просто перемещение указателя на свободную сторону и переместить на расстояние, равное размеру объекта Вот и все. Если сборщик мусора выбирает Serial, ParNew, основанный на алгоритме сжатия, виртуальная машина применяет этот метод распределения. При использовании коллектора с процессом Compact (очистки) обычно используются коллизии указателей.
Распределение свободного списка:
если память не является регулярной, используемая память и неиспользуемая память чередуются, тогда виртуальная машина будет использовать свободный список для выделения памяти для объекта. Это означает, что виртуальная машина ведет список, записывает, какие блоки памяти доступны, находит достаточно большое пространство в списке, чтобы разделить его на экземпляр объекта при перераспределении, и обновляет содержимое списка. Этот метод распределения становится «Свободным списком».

Обработка проблем параллелизма:

  • Использование CAS в сочетании с неудачной повторной попыткой для обеспечения атомарности обновления.
  • Выделить область TLAB для каждого потока в области Eden — задается установкой параметра -XX:+UseTLAB (механизм блокировки области),

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

Установите информацию заголовка объекта объекта:
сохраните класс объекта (то есть информацию метаданных класса), HashCode объекта, информацию GC объекта и информацию блокировки в заголовке объекта объекта. Настройка этого процесса зависит от реализации JVM.

Выполните метод init для инициализации:
с точки зрения Java-программы инициализация официально начинается. Инициализируйте переменные-члены, выполните созданный блок кода, вызовите конструктор класса и назначьте первый адрес объекта в куче ссылочной переменной.
Вообще говоря (определяемое выполнением инструкции invokespecial в байт-коде), за новой инструкцией следует метод выполнения, который инициализирует объект в соответствии с пожеланиями программиста, так что создается действительно пригодный для использования объект.

Структура памяти объекта

вставьте сюда описание изображения

Заголовок объекта:
заголовок объекта состоит из двух частей, а именно метаданных времени выполнения (Mark Word) и указателя типа.Если это массив, необходимо записать длину массива.

  • Метаданные времени выполнения: HashCode, возраст создания GC, флаги состояния блокировки, блокировки, удерживаемые потоками, смещенные идентификаторы потоков и смещенные временные метки.
  • Указатель типа: указывает на метаданные класса InstanceKlass, чтобы определить тип объекта. На самом деле он указывает на метаинформацию класса, хранящуюся в области метода.

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

Правила: одни и те же поля всегда назначаются вместе, переменные, определенные в родительском классе, всегда появляются перед дочерним классом, если параметр CompactFields имеет значение по умолчанию true, узкие переменные дочернего класса могут быть вставлены в пробел переменная родительского класса.

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

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

Как JVM получает доступ к своему внутреннему экземпляру объекта через ссылку на объект в кадре стека?
вставьте сюда описание изображения

Существует два способа доступа к объектам:

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

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

рекомендация

отblog.csdn.net/Lzy410992/article/details/117732100