Жизненный цикл объекта в Java

Java
Жизненный цикл объекта в Java

предисловие

  В реальном мире каждый является объектом, от рождения до роста и до смерти — это полный жизненный цикл. В компьютерном мире объект также имеет свой жизненный цикл, включая создание объекта, расположение объекта в памяти, доступ к объекту и уничтожение объекта. Это верно для объектов в C++, и то же самое верно для объектов в Java. Просто жизненный цикл объекта в C++ полностью контролируется программистом, включая создание, использование и переработку. В Java программисты должны нести ответственность только за создание и использование объектов, а рекламация передается виртуальной машине Java. Создать объект легко, уничтожить объект сложно. Как Java-программисты, несмотря на то, что виртуальная машина выполняет за нас переработку объектов, это не означает, что нам не нужно понимать полный жизненный цикл объекта. Только понимая процесс объекта от рождения до смерти, мы можем глубоко любить и ненавидеть объект.

создание объекта

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

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

  • Загрузите в память файл класса, в котором находится объект (то есть скомпилированный файл .class).
  • Выделить блок памяти размером с объект класса в куче
  • Инициализировать значение памяти, где находится объект, равным 0
  • Инициализировать заголовок объекта, включая хэш-код объекта, возраст генерации объекта GC и другую информацию.
  • Вызов функции инициализации класса для инициализации объектов на уровне Java.

   Блок-схема выглядит следующим образом:

2. Как выделить память объекта

   Все мы знаем, что Java необходимо выделять память для генерации объектов.Как виртуальная машина выделяет часть памяти из пула памяти вновь созданному объекту? Существует два основных способа реализации виртуальной машины:

  • столкновение указателя

Если память в куче Java абсолютно обычная, со всей используемой памятью с одной стороны, свободной памятью с другой и указателем посередине как индикатором демаркационной точки, то выделенная память как раз и есть. к свободному пространству на расстояние, равное размеру объекта.Этот метод выделения называется "Bump the Pointer".

  • Метод свободного списка:

Если память в куче Java не является регулярной, а используемая память и свободная память чередуются, нет возможности просто выполнить коллизии указателей, и виртуальная машина должна поддерживать список доступных блоков памяти. найти достаточно большое место из списка, чтобы разделить его на экземпляр объекта, и обновить записи в списке.Этот метод выделения называется «свободный список» (Free List).

   Вышеуказанные два метода рассматривают только выделение объектной памяти, на самом деле есть еще и восстановление памяти, что тоже нужно делать виртуальной машине. Выделение и освобождение памяти много обсуждается в C/C++, для создания объектов в Java это не имеет значения, нужно только знать, что есть два способа выделения объектной памяти, каждый из которых имеет свои преимущества и недостатки. Еще одна вещь, я использую nginx только для проектирования выделения и повторного использования памяти объектов. nginx играет управление ресурсами памяти проницательно и ярко. Если вам интересно, вы можете взглянуть на соответствующий исходный код.

макет объекта

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

  1. Слово метки в заголовке объекта имеет размер 32 и 64 бита в 32- и 64-разрядных виртуальных машинах, а указатель типа одинаков.Поля в заголовке объекта имеют следующие характеристики:
  • Mark Word разработан как нефиксированная структура данных, чтобы хранить как можно больше информации в очень небольшом пространстве, и он будет повторно использовать свое собственное пространство для хранения в соответствии с состоянием объекта. Конкретные эффекты мультиплексирования различных состояний показаны на следующем рисунке.

  • Указатель типа указывает на объект Class того класса, которому принадлежит объект, но это поле не является обязательным для всех виртуальных машин. Посмотрите, как виртуальная машина реализует доступ к объектам, что обсуждается в следующем разделе.
  • Кроме того, если объект является массивом, информация о длине массива должна храниться в заголовке объекта. Это позволяет виртуальной машине определять размер объекта по метаданным объекта.
  1. Данные экземпляра объекта видны и могут контролироваться пользователем, в том числе унаследованы от всех родительских классов (до Object) и определены в подклассах. Следует отметить, что все статические переменные, локальные переменные и функции не включаются в данные экземпляра памяти объекта:

Статические переменные и функции принадлежат классам, и существует только одна копия класса, которая сохраняется в области методов при загрузке класса. Функции также существуют в области методов как метаданные класса (в то же время на них будет влиять JIT-компиляция). Локальные переменные динамически размещаются в стеке во время выполнения метода, и их основное местонахождение — таблица локальных переменных.

  1. Заполнение выравнивания не обязательно существует и не имеет особого значения, оно просто действует как заполнитель. Поскольку система автоматического управления памятью HotSpot VM требует, чтобы начальный адрес объекта был целым числом, кратным 8 байтам, иными словами, размер объекта должен быть целым числом, кратным 8 байтам. Часть заголовка объекта точно кратна 8 байтам (1 или 2 раза), поэтому, когда часть данных экземпляра объекта не выровнена, она должна быть дополнена дополнением выравнивания.

  С++ имеет широко распространенную книгу «Углубленное понимание объектной модели С++», которая посвящена объектной модели С++ и была написана в виде книги. Видно, что по сравнению с объектами C++ Java намного проще. Чтобы вычислить размер объекта в C++, используйте sizeof напрямую. В Java это не так прямолинейно.Если вы хотите узнать больше о размере объектов Java в памяти, см.Сколько памяти занимает объект JavaПопрактикуйтесь в этой статье сами. На самом деле, если вы знаете состав объекта в памяти (заголовок, данные экземпляра и заполнение) и размер каждого типа поля в данных экземпляра, вы можете легко рассчитать общий размер объекта.

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

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

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

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

  • Прямой указатель: данные экземпляра объекта сохраняются в ссылке, что согласуется с тем, что понимает большинство людей. В этот момент указатель данных типа объекта помещается в Mark Word (если вы не понимаете, вы можете оглянуться назад на введение заголовка объекта). Конкретная схема доступа выглядит следующим образом:

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

   Теперь, когда вас спросят, что сохраняется в справочнике, не спешите отвечать, что это адрес объекта, а может быть адрес адреса объекта.

разрушение объектов

   Это самая сложная часть жизненного цикла объекта и суть Java. В C++, если новый объект больше не нужен, его необходимо УДАЛИТЬ вручную. В Java виртуальная машина используется для завершения рециркуляции, а объектная память виртуальной машины GC (сборка мусора) должна решать следующие две проблемы:

Когда перерабатывать?

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

  1. метод счетчика ссылок

  • Принцип: добавьте к объекту счетчик ссылок.Всякий раз, когда есть место для ссылки, значение счетчика увеличивается на 1; когда ссылка недействительна, значение счетчика уменьшается на 1; объект, счетчик которого равен 0 в любой время невозможно использовать снова. , как Объект А на рисунке выше.
  • Преимущества: принцип прост, использование простое, а эффективность суждения высока.
  • Недостаток: сложно решить проблему циклического применения между объектами, если циклические ссылки не запрещены.
  • Практика: технология Microsoft COM, язык Python и т. д.
  1. Оценка доступности

  • Принцип: Через ряд объектов, называемых «Корни GC» в качестве отправной точки, поиск начинается с этих узлов, а путь, пройденный поиском, называется цепочкой ссылок.Когда объект не имеет ссылки на корни GC Когда цепочка связан (говоря языком теории графов, объект недоступен из GC Roots), он доказывает, что объект недоступен, например, Object5, Object6 и Object7 на приведенном выше рисунке.
  • Преимущества: он может решить проблему циклических ссылок и удовлетворить потребности различных ситуаций.
  • Недостатки: сложная реализация и низкая эффективность обхода.
  • Практика: основная виртуальная машина Java.

Как перерабатывать

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

  • Алгоритм Mark-Sweep: он разделен на два этапа «маркировки» и «подметания»: сначала помечаются все объекты, которые необходимо переработать, и все помеченные объекты единообразно восстанавливаются после завершения маркировки.
  • Алгоритм копирования: он делит доступную память на два блока одинакового размера в соответствии с их емкостью и использует только один из них за раз. Когда память этого блока израсходована, уцелевшие объекты копируются в другой блок, а затем однократно очищается использованное пространство памяти.
  • Алгоритм Mark-Compact: процесс маркировки аналогичен алгоритму «mark-clean», но следующим шагом является не прямая очистка перерабатываемых объектов, а перемещение всех уцелевших объектов в один конец, а затем прямая очистка конец памяти за пределами.
  • Алгоритм генерации-сбора: Алгоритм сбора, этот алгоритм не имеет каких-либо новых идей, но делит память на несколько блоков в соответствии с жизненным циклом объекта. Как правило, куча Java делится на новое поколение и старое поколение, чтобы можно было выбрать наиболее подходящий алгоритм сбора в соответствии с характеристиками каждого поколения. .

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

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

Суммировать

Чен Шуо, автор многопоточной сетевой библиотеки Muduo под C++, упомянул в своей книге «Многопоточное серверное программирование в Linux», что «создавать объекты легко, но уничтожать их слишком сложно», и я, наконец, понял это после прочтения руководства по Java. управление жизненным циклом объекта Не ложно. Спасибо великим изобретателям Java за то, что они предоставили пользователям самую простую часть управления жизненным циклом объекта и оставили самую сложную часть для себя.

Категории