Что происходит, когда вы создаете новый объект

Java
Что происходит, когда вы создаете новый объект

Введение

Как вы знаете, Java — это объектно-ориентированный язык программирования. Когда мы обычно пишем код, мы постоянно манипулируем различными объектами, поэтому когда вы пишете кодUser user = new User();Что такое JVM, когда это строка кода?

Во-вторых, понять объект

1. Схема памяти

Структура памяти объекта в виртуальной машине Hotspot разделена на три части: заголовок объекта, данные экземпляра и заполнение выравнивания.

  • Заголовок объекта состоит из двух частей информации: первая часть используется для хранения текущих данных самого объекта (HashCode, возраст генерации сборщика мусора, флаг состояния блокировки и т. д.). Другая часть — это указатель типа, который указывает на метаданные своего класса, и виртуальная машина использует этот указатель, чтобы определить, экземпляром какого класса является объект (если используется метод пула дескрипторов, его не будет). Если это массив, также будет запись длины массива, как показано в следующей таблице:

    содержание инструкция
    Mark Word Хэш-код объекта или информация о блокировке и т. д.
    Class Metadata Address указатель данных типа объекта
    Array length длина массива
    Mark Word — это нефиксированная структура данных, которая позволяет хранить как можно больше информации на очень маленьком пространстве, повторно используя собственное пространство для хранения в соответствии с состоянием объекта. Содержимое хранилища в каждом состоянии показано в следующей таблице:
    бит флага государство
    :-------: :------------:
    01 не заблокирован
    00 Легкий замок
    10 Блокировка в супертяжелом весе
    11 маркеры ГХ
    01 может быть предвзятым
  • Часть данных экземпляра — это эффективная информация, которая действительно хранится, то есть содержимое различных типов полей, определенных в коде. Унаследовано ли оно от родительского класса или в дочернем классе.

  • Заполнение выравнивания не требуется, оно действует только как заполнитель, потому что виртуальная машина HotSpot требует, чтобы начальный адрес объекта был целым числом, кратным 8 байтам.

2. Доступ к объекту

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

  • Метод прямого указателя (реализация HotSpot): адрес объекта в куче хранится непосредственно в ссылке. Преимущество состоит в том, что скорость позиционирования высока, а недостаток в том, что необходимо изменить саму ссылку на движение объекта (движение объекта во время GC).

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

3. Создать объектный процесс

Основная информация об объекте представлена ​​выше, теперь поговорим о самом процессе создания объекта:

  1. Когда виртуальная машина встречает новую инструкцию, она проверяет, могут ли параметры этой инструкции найти символическую ссылку на класс в пуле констант, и проверяет, загружен ли представленный класс загрузчиком классов. Если он не загружен, то сначала должен быть загружен класс.
  2. После того, как проверка загрузки класса пройдена, виртуальная машина выделит память для нового объекта, а размер памяти, необходимой объекту, можно будет определить после загрузки класса.
  3. После того, как выделение памяти завершено, виртуальная машина должна инициализировать объект нулевым значением, чтобы гарантировать, что объектпеременная экземпляраЕго можно использовать непосредственно в коде без присвоения начального значения. Переменные класса инициализируются нулевым значением на этапе подготовки загрузки класса.
  4. Установите необходимую информацию для заголовка объекта, например, как найти информацию о метаданных класса, HashCode объекта и возраст создания GC.
  5. После вышеперечисленных операций новый объект создан, но метод не выполнен, а все поля равны нулю. В это время необходимо выполнить метод (метод конструктора) для инициализации объекта в соответствии с пожеланиями программиста. Операция инициализации переменных класса завершается в методе на этапе инициализации загрузки класса.

Существует два способа выделения памяти:

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

GC запускается, когда не может быть найдено достаточно памяти

Решение проблемы параллелизма при выделении памяти:

  • Синхронизируйте действие по выделению памяти — используйте метод повторной попытки CAS при сбое, чтобы обеспечить атомарность операции обновления.
  • Каждый поток предварительно выделяет небольшой объем памяти в куче, который называется локальным буфером выделения потока (TLAB). Какой поток должен выделить память в своем TLAB. Блокировка синхронизации требуется только тогда, когда TLAB израсходован и выделяется новый TLAB. Задается параметром -XX:+/-UseTLAB.

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

A a = new A();

Простое действие декомпозиции нового объекта:

  1. Выделить место в памяти для объекта
  2. Инициализировать объект
  3. Установите ссылку, указывающую на выделенный адрес памяти

Среди них переупорядочение инструкций произойдет между шагами 2 и 3, что вызовет проблемы, если доступ к объекту будет осуществлен до инициализации в многопоточности.Эта проблема существует в режиме блокировки двойного обнаружения одноэлементного режима. Вы можете использовать volatile, чтобы предотвратить переупорядочивание инструкций для решения проблемы;