«Учебное пособие по собеседованию» — Очки знаний JVM

Java
«Учебное пособие по собеседованию» — Очки знаний JVM

Обзор

1. Что такое виртуальная машина?

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

Кроссплатформенность — это программа на Java (включая файлы байт-кода), а не JVM. JVM разработана на языке C/C++, который представляет собой скомпилированный машинный код и не может быть кросс-платформенным.Разные версии JVM необходимо устанавливать на разных платформах.

2. Компоненты JVM

  • Загрузчик классов загружает необходимые классы в JVM при запуске JVM или при запуске класса.

  • Область памяти разделена на несколько областей для имитации функциональных модулей хранения, записи и планирования на реальной машине, таких как регистры различных функций на реальной машине или регистратор указателя ПК.

  • Механизм выполнения, задачей механизма выполнения является выполнение инструкций байт-кода, содержащихся в файле класса, что эквивалентно ЦП на реальной машине.

  • Вызов собственного метода, код, который вызывает собственный метод, реализованный на C или C++, возвращает результат.

1. Загрузчик классов

С момента загрузки класса в память виртуальной машины до момента его выгрузки из памяти весь его жизненный цикл делится на 7 этапов.Загрузка,Проверка,Подготовка,разрешение,Инициализация,Использование (использование),Разгрузка. Три части проверки, подготовки и синтаксического анализа в совокупности называются соединением. 7 стадий происходят в следующем порядке:

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

1.1, загрузка

На этапе загрузки виртуальная машина должна сделать 3 вещи:

  • Получите двоичный поток байтов, определяющий этот класс по его полному имени.
  • Преобразует статическую структуру хранения, представленную этим потоком байтов, в структуру данных времени выполнения области метода.
  • Объект java.lang.Class, представляющий этот класс, создается в памяти как запись доступа к различным структурам данных этого класса в области методов.
加载阶段完成后,虚拟机外部的 二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个java.lang.Class类的对象,这样便可以通过该对象访问方法区中的这些数据。 

1.2. Проверка

Этап проверки, в основном, цель этого этапа — убедиться, что информация, содержащаяся в потоке байтов файла класса, соответствует требованиям виртуальной машины и не будет угрожать безопасности самой виртуальной машины.

Этап проверки в основном завершает следующие четыре этапа действий по проверке:

文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。

元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。

字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。

符号引用验证:确保解析动作能正确执行。

1.3 Подготовка

Фаза подготовки — это фаза формального выделения памяти для переменных класса и установки начальных значений, а память, используемая этими переменными, будет выделена в области метода.

进行内存分配的仅包括类变量(static),而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在Java堆中。

初始值通常情况下是数据类型默认的零值(如0、0L、null、false等)

1.4 Анализ

Фаза синтаксического анализа — это процесс замены символических ссылок в пуле констант виртуальной машины прямыми ссылками. Действие синтаксического анализа в основном выполняется для 7 типов символов, таких как класс или интерфейс, поле, метод класса, метод интерфейса, тип метода, дескриптор метода и квалификатор места вызова.

符号引用:简单的理解就是字符串,比如引用一个类,java.util.ArrayList 这就是一个符号引用,字符串引用的对象不一定被加载。

直接引用:指针或者地址偏移量。引用对象一定在内存(已经加载)。

1.5, инициализация

Инициализация класса — это последний шаг загрузки класса.За исключением этапа загрузки, пользователь может участвовать через настраиваемый загрузчик классов, а остальные этапы полностью контролируются виртуальной машиной. Код Java фактически не выполняется до фазы инициализации.

Основная задача инициализации класса состоит в том, чтобыСтатическим переменным присваиваются начальные значения, заданные программой.

如static int a = 100;在准备阶段,a被赋默认值0,在初始化阶段就会被赋值为100。

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

  • 1. Используйте новую инструкцию байт-кода для создания экземпляра класса или используйте getstatic, putstatic для чтения или установки значения статического поля (кроме констант, помещенных в пул констант), или при вызове статического метода соответствующий класс должен быть переинициализирован.

  • 2. При выполнении рефлексивного вызова класса через метод пакета java.lang.reflect, если класс не был инициализирован, его необходимо сначала инициализировать.

  • 3. При инициализации класса, если обнаруживается, что его родительский класс не был инициализирован, он сначала инициирует инициализацию родительского класса.

  • 4. При запуске виртуальной машины пользователю необходимо указать основной класс (класс, содержащий метод main()), и виртуальная машина сначала инициализирует этот класс.

  • 5. При использовании поддержки динамического языка jdk1.7, если последним результатом синтаксического анализа экземпляра java.lang.invoke.MethodHandle является дескриптор метода REF_getStatic, REF_putStatic и RE_invokeStatic, а класс, соответствующий этому дескриптору метода, не имеет был инициализирован, он должен быть запущен в первую очередь его инициализация.

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

Создание объектов в Java — это процесс выделения памяти в куче.Упомянутое здесь создание объектов ограничено обычными объектами Java, созданными с помощью ключевого слова new, за исключением создания объектов-массивов.

Когда виртуальная машина встречает инструкцию, содержащую new, она выполняет ряд операций по созданию объекта:

2.1, проверьте, загружен ли класс

1. Проверить, есть ли в константном пуле символическая ссылка на класс, к которому относится создаваемый объект; Если в константном пуле нет символической ссылки на этот класс, значит, этот класс не был определен! бросить ClassNotFoundException;

2. Затем проверьте, был ли загружен JVM класс, представленный этой символической ссылкой; Если класс не был загружен, найдите файл класса класса и загрузите его в область методов; Если класс был загружен JVM, подготовьтесь к выделению памяти для объекта;

2.2 Выделить память для объектов

3. Определить объем памяти, необходимый классу, в соответствии с информацией о классе в области методов; Объем памяти, требуемый объектом, можно определить после того, как будет определен класс, к которому принадлежит объект! И размер памяти всех объектов, созданных классом, одинаков! Когда класс загружается в область методов, JVM знает размер памяти, необходимый для каждого объекта, созданного классом. 4. Разделить соответствующий размер памяти из кучи на новый объект; Существует два способа выделения памяти в куче: столкновение указателя Если сборщик мусора JVM использует алгоритм копирования или алгоритм пометки для очистки, то свободная память в куче представляет собой полную область, а свободная память и используемая память помечаются указателем. Затем при выделении памяти под объект просто перемещайте указатель. Поэтому такой способ выделения памяти путем перемещения указателя по полностью свободной области называется «коллизией указателей». бесплатный список Если сборщик мусора JVM принимает алгоритм маркировки-очистки, свободная и используемая области в куче чередуются, поэтому необходим «свободный список» для записи того, какие области в куче являются свободными областями, так что когда объекты создаются в соответствии с этим Zhang "список свободных" находит свободные области и выделяет память. Подводя итог: какой метод выделения памяти использует JVM, зависит от того, какой сборщик мусора он использует.

多线程并发时会出现正在给对象 A 分配内存,还没来得及修改指针,对象 B 又用这个指针分配内存,这样就出现问题了。
解决这种问题有两种方案:
第一种,是采用同步的办法,使用 CAS 来保证操作的原子性。
另一种,是每个线程分配内存都在自己的空间内进行,即是每个线程都在堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB),分配内存的时候再TLAB上分配,互不干扰。可以通过 -XX:+/-UseTLAB 参数决定。

2.3. Инициализировать нулевое значение для выделенного пространства памяти

5. Присвоить начальные значения переменным-членам в объекте (инициализация по умолчанию);

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

2.4. Произведите другие настройки объекта

6. Установить информацию в шапке объекта;

Класс, к которому он принадлежит, информация о метаданных класса, хэш-код объекта, возраст поколения GC и другая информация.

2.5. Выполнение метода инициализации

7. Вызвать конструктор объекта для инициализации

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

Порядок инициализации:

在new B一个实例时首先要进行类的装载。(类只有在使用New调用创建的时候才会被java类装载器装入)

在装载类时,先装载父类A,再装载子类B

装载父类A后,完成静态动作(包括静态代码和变量,它们的级别是相同的,按照代码中出现的顺序初始化)

装载子类B后,完成静态动作

类装载完成,开始进行实例化

在实例化子类B时,先要实例化父类A2,实例化父类A时,先成员实例化(非静态代码)
父类A的构造方法
子类B的成员实例化(非静态代码)
子类B的构造方法

先初始化父类的静态代码--->初始化子类的静态代码-->初始化父类的非静态代码--->初始化父类构造函数--->初始化子类非静态代码--->初始化子类构造函数

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

3.1 Заголовок объекта (markword)

  • Первая часть используется для хранения данных времени выполнения самого объекта, таких как хэш-код (HashCode), возраст генерации GC, флаг состояния блокировки, блокировки, удерживаемые потоками, смещенный идентификатор потока, смещенная отметка времени, возраст создания объекта, эта часть информация называется «Mark Word»; Mark Word разработан как нефиксированная структура данных для хранения как можно большего количества информации в очень небольшом пространстве, и он будет повторно использовать свое собственное пространство для хранения в соответствии со своим собственным состоянием.
  • Вторая часть — это указатель типа, то есть указатель, который объект указывает на метаданные своего класса, и виртуальная машина использует этот указатель, чтобы определить, экземпляром какого класса является объект;
Klass Word  这里其实是虚拟机设计的一个oop-klass model模型,这里的OOP是指Ordinary Object Pointer(普通对象指针),看起来像个指针实际上是藏在指针里的对象。而 klass 则包含 元数据和方法信息,用来描述 Java 类。它在64位虚拟机开启压缩指针的环境下占用 32bits 空间。
  • Если объект представляет собой массив Java, в заголовке объекта также должна быть часть данных, в которой записана длина массива. Поскольку виртуальная машина может определить размер объекта Java с помощью информации метаданных обычного объекта Java, но размер массива не может быть определен из метаданных массива.

В 32-битной системе заголовок объекта составляет 8 байт, а в 64-битной — 16 байт [указатель сжатия не включен, 12 байт после его включения].

Предполагая, что текущий 32-битный, в случае, если объект не заблокирован. 25 бит используются для хранения хэш-кода объекта, 4 бита используются для хранения возраста поколения, 2 бита используются для хранения флага блокировки, а 1 бит фиксируется на 0.

Данные хранятся в разных условиях:

Среди них флаг блокировки требует особого внимания. Бит флага блокировки и то, является ли это смещенной блокировкой, соответствует уникальному состоянию блокировки.

Состояние блокировки делится на четыре состояния без блокировки, смещенные блокировки, облегченные блокировки и тяжелые блокировки.

Интервальное значение заголовка объекта в разных состояниях показано на рисунке.

3.2 Данные экземпляра

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

На порядок хранения этой части влияет параметр стратегии выделения виртуальной машины (FieldsAllocationStyle) и порядок, в котором поля определены в исходном коде Java.

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

3.3. Заполнение

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

由于HotSpot规定对象的大小必须是8的整数倍,对象头刚好是整数倍,如果实例数据不是的话,就需要占位符对齐填充。

3.4. Предполагаемый размер объекта

В 32-битной системе при использовании new Object() JVM выделит 8 байтов пространства (Mark Word + type pointer), а 128 объектов Object будут занимать 1 КБ пространства. Если это new Integer(), то в объекте есть значение int, которое занимает 4 байта, этот объект 8+4=12 байт, после выравнивания объект занимает 16 байт.

Выше приведены лишь некоторые простые объекты, так как же устроены внутренние свойства объектов?

Class A {
    int i;
    byte b;
    String str;
}

Заголовок объекта занимает 'Mark Word'4 + 'type pointer'4 = 8 байт, byte имеет длину 8 бит и занимает 1 байт, int имеет длину 32 бита и занимает 4 байта, String имеет только ссылки и занимает 4 байта; Тогда объект А занимает в сумме 8+1+4+4=17 байт, согласно принципу 8-байтового выравнивания размер объекта составляет 24 байта.

Этот расчет кажется правильным, размер объекта действительно составляет 24 байта, но заполнение неверно:

В HotSpot VM при размещении объектов зазор составляет 4 байта (в 32-битном и 64-битном режимах сжатия).В приведенном выше примере байт после int имеет только 3 байта в зазоре. Строковой ссылке на объект требуется 4 байта для хранения, поэтому между байтом и ссылкой на объект будет выравнивание по 3 байтам. 7-байтовое выравнивание. Структурная схема объекта в это время представлена ​​на следующем рисунке:

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

对象的访问方式由虚拟机决定,java虚拟机提供两种主流的方式
1.句柄访问对象
2.直接指针访问对象。(Sun HotSpot使用这种方式)

4.1, ручка доступа

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

Достоинства: Стабильный адрес дескриптора хранится в ссылке, при перемещении объекта [перемещение объекта во время сборки мусора является нормой] нужно менять только указатель данных экземпляра в дескрипторе, а ссылка [ref] сам менять не надо.

4.2, прямой указатель

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

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

5. Область памяти JVM

5.1, стек виртуальных машин

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

В стеке виртуальной машины Java могут возникать два типа исключений:

  • Глубина стека, запрошенная потоком, больше, чем глубина стека, разрешенная виртуальной машиной, иStackOverflowError

  • Пространство стека виртуальной машины можно динамически расширять.Исключение OutOfMemory

  • Ссылка на расширение:кадр стека

5.2, локальный стек методов

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

5.3, счетчик программ

  • Счетчик программ — это небольшая область памяти, которая является частной для потока и может рассматриваться как индикатор номера строки текущего потока.
  • Основная функция счетчика программ состоит в том, чтобы записывать состояние потока во время его выполнения, чтобы поток мог продолжать выполнение из состояния, когда он был в последний раз приостановлен при его пробуждении.
  • Счетчик программ — единственный, который не указан в спецификации виртуальной машины Java каким-либо образом.Области для ситуаций OOM, так что эта область не нуждается в GCed

5.4, ​​локальная память

  • Разделяемая область потока в Java 8, локальная память, также известная как память вне кучи, включая метапространство и область методов.
  • Основная информация о классе хранения, константы, статические переменные, скомпилированный код компилятора реального времени и т. д. Эта часть реализована в куче и управляется сборщиком мусора, но поскольку постоянная генерация имеет верхний предел -XX:MaxPermSize
  • Поэтому, если вы динамически генерируете классы (помещаете информацию о классе в постоянную генерацию) или выполняете String.intern в больших количествах (помещаете строки полей в постоянную область постоянной генерации), легко вызвать OOM.Некоторые люди говорят, что вы можно установить достаточно большую постоянную генерацию, но трудно определить подходящий размер, на который сильно влияет количество классов и количество констант.
  • Поэтому в Java 8 реализация области метода перемещена в метапространство в локальной памяти, так что область метода не контролируется JVM, и сборщик мусора не будет выполняться, что повышает производительность (остановка произойдет, когда сборщик мусора Word, производительность будет затронута в определенной степени, о чем будет сказано позже), и нет исключения OOM из-за предельного размера постоянного поколения (при условии, что общая память составляет 2G, JVM выделена Памяти 100M, по идее метапространство можно выделить 2G -100M=1.9G, размера пространства достаточно), что также удобно для унифицированного управления в метапространстве.
  • Таким образом, эта область не нуждается в GCed после Java 8.
  • Ссылка на расширение:Освобождение памяти вне кучи

5.5 Куча

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

6. Оценка выживания объекта

  • подсчет ссылок
  • Анализ доступности

6.1 Подсчет ссылок

У каждого объекта есть атрибут счетчика ссылок.При добавлении новой ссылки счетчик увеличивается на 1, а при освобождении ссылки уменьшается на 1. Когда счетчик равен 0, его можно использовать повторно. Этот метод прост и не может решить проблему циклической ссылки объектов друг на друга. В настоящее время используются Python, ActionScript3 и другие языки.

6.2, анализ доступности

Начиная с GC Roots, поиск идет вниз, и путь, пройденный поиском, называется цепочкой ссылок. Когда объект не имеет какой-либо цепочки ссылок, связанной с корнями GC, объект считается недоступным. Недоступный объект. В настоящее время используются Java, C# и другие языки.

GC Roots 对象:
虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中的类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中 JNI(即一般说的 Native 方法)中引用的对象。

Как определить бесполезные классы:

该类所有实例都被回收(Java 堆中没有该类的对象)。
加载该类的 ClassLoader 已经被回收。
该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方利用反射访问该类。

6.3, доработать

Метод finalize() вызывается GC (сборщиком мусора) перед освобождением памяти объекта.

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

6.4 Тип ссылки на объект

  • сильная цитата
  • Мягкая ссылка
  • Слабая ссылка (WeakReference)
  • PhantomReference

6.4.1 Сильная ссылка

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

6.4.2 Мягкие ссылки

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

6.4.3 Слабые ссылки

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

6.4.4, виртуальная ссылка

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

расширять

Решите проблемы OOM с мягкими и слабыми ссылками. HashMap используется для сохранения отношения сопоставления между путем к изображению и мягкой ссылкой, связанной с соответствующим объектом изображения.Когда памяти недостаточно, JVM автоматически восстанавливает пространство, занимаемое этими кэшированными объектами изображения, таким образом эффективно избегая проблема ООМ. Реализует кэширование объектов Java через программные ссылки. Например, если мы создаем класс Person, если нам нужно каждый раз запрашивать информацию о человеке, даже если она была запрошена всего несколько секунд назад, нам нужно перестроить экземпляр, что приведет к большому потреблению объектов Person. , и из-за этих объектов жизненный цикл относительно короткий, что приведет к тому, что несколько сборщиков мусора повлияют на производительность. В настоящее время комбинация мягких ссылок и HashMap может создать кеш для обеспечения производительности.

7. Алгоритм сборки мусора

  • алгоритм маркировки-развертки
  • алгоритм маркировки-сопоставления
  • алгоритм репликации
  • Алгоритм сбора поколений

7.1, отметка-ясно

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

недостаток:

  • 1. Проблема эффективности, эффективность двух процессов маркировки и очистки невысока.
  • 2. Проблема с пространством. После снятия метки будет создано большое количество прерывистых фрагментов памяти. Слишком много фрагментов пространства может привести к тому, что, когда в процессе выполнения программы необходимо выделить более крупный объект, он не сможет найти достаточно непрерывной памяти и должен заранее вызвать другой метод, действие по сбору мусора.

7.2. Организация маркировки

Алгоритм сортировки меток аналогичен алгоритму очистки меток, но после маркировки объекта он не очищает непосредственно перерабатываемые объекты, а перемещает все уцелевшие объекты в один конец, а затем непосредственно очищает память за границей.

преимущество:

  • 1. Алгоритм очистки относительной метки решает проблему фрагментации памяти.
  • 2. После того, как нет фрагментации памяти, выделение памяти для создания объекта также происходит быстрее (для выделения можно использовать TLAB).

недостаток:

  • 1. Проблема эффективности (такая же, как и алгоритм удаления меток) эффективность двух процессов маркировки и сортировки невысока.

7.3 Алгоритм репликации

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

преимущество:

  • 1. Высокая эффективность, отсутствие фрагментации памяти.

недостаток:

  • 1. Пустой объем памяти.
  • 2. Алгоритм сбора копий должен выполнять больше операций копирования, когда показатель выживания объекта высок, и эффективность становится ниже.

7.4 Алгоритм генерации

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

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

Левая половина рисунка — это область памяти до высвобождения, а правая половина — область памяти после высвобождения.

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

Улучшенный алгоритм саморепликации

Сегодняшние коммерческие виртуальные машины используют этот алгоритм сбора для повторного использования нового поколения.Специальные исследования IBM показывают, что 98% объектов нового поколения являются «мертвыми», поэтому нет необходимости делить их по соотношению 1:1. Вместо этого память делится на большее пространство Эдема и два меньших пространства Выживших, каждый раз используя Эдем и одного Выжившего. При переработке скопируйте уцелевшие объекты в Эдеме и Выжившем в другое пространство Выжившего за один раз и, наконец, очистите Эдем и только что использованное пространство Выжившего. Соотношение размеров виртуальной машины Eden и 2 Survivors of HotSpot по умолчанию составляет 8:1:1, то есть доступное пространство памяти в каждом новом поколении составляет 90% (80%+10%) от всей емкости нового поколения, и только 10% памяти будет "утрачено". Конечно, 98% объектов, которые могут быть переработаны, являются только данными в общих сценариях.У нас нет возможности гарантировать, что не более 10% объектов переживет каждую переработку.Когда места Survivor недостаточно, нам нужно полагаться на другую память (здесь имеется в виду старость) для обработки.

8. Точка безопасности

8.1 Точка безопасности

SafePoint, как следует из названия, относится к некоторым конкретным местоположениям.Когда поток запускается в эти местоположения, может быть определено некоторое состояние потока (хорошо описано представление потока о состоянии Java-машины), например, запись состояния OopMap. для определения корневой информации сборщика мусора, чтобы JVM могла безопасно выполнять некоторые операции, такие как запуск сборщика мусора.

Конкретные местоположения, на которые ссылается SafePoint:

  • Конец цикла (чтобы большой цикл никогда не попадал в Safepoint, пока другие потоки ожидают его входа в Safepoint).
  • до возврата метода.
  • После вызова метода Call .
  • Место, где было выдано исключение.

8.2 Безопасная зона

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

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

9. Сборщик мусора JVM

коллекционер Последовательный, параллельный или параллельный Новое поколение/Старое поколение алгоритм Цель Применимая сцена
Serial сериал Кайнозой алгоритм репликации Приоритет скорости отклика Клиентский режим в однопроцессорной среде
Serial Old сериал старость Отметить-организовать Приоритет скорости отклика Режим клиента и план резервного копирования CMS в среде с одним ЦП
ParNew параллельно Кайнозой алгоритм репликации Приоритет скорости отклика Взаимодействие с CMS в режиме сервера в многопроцессорной среде
Parallel Scavenge параллельно Кайнозой алгоритм репликации приоритет пропускной способности Задачи, которые работают в фоновом режиме без особого взаимодействия
Parallel Old параллельно старость Отметить-организовать приоритет пропускной способности Задачи, которые работают в фоновом режиме без особого взаимодействия
CMS параллелизм старость отметка-ясно Приоритет скорости отклика Java-приложения сосредоточены на Интернет-сайтах или системных серверах B/S.
G1 параллелизм both Алгоритм «Отметить-Организовать+Копировать» Приоритет скорости отклика Серверно-ориентированное приложение, заменяющее CMS в будущем
ZGC параллелизм both Алгоритм «Отметить-Организовать+Копировать» Приоритет скорости отклика Серверно-ориентированное приложение, заменяющее CMS в будущем

9.1 Серийный (Новое поколение)

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

9.2, ParNew (новое поколение)

  • Многопоточная версия сборщика Serial, единственное отличие от Serial в том, что он использует несколько потоков для сборки мусора.
  • Помимо Serial, это единственный сборщик, который можно использовать с CMS.
  • Используется как сборщик молодого поколения, алгоритм репликации.

9.3, Parallel Scavenge (новое поколение)

Используется как сборщик молодого поколения, алгоритм репликации. Сосредоточившись на высокой пропускной способности, он может эффективно использовать процессорное время и выполнять вычислительные задачи программы как можно быстрее.Он в основном подходит для задач, которые не требуют слишком большого взаимодействия в фоновом режиме. Сборщик Parallel Scavenge предоставляет два параметра для точного управления пропускной способностью: параметр -XX:MaxGCPauseMillis, который управляет максимальным временем приостановки сборки мусора, и параметр -XX:GCTimeRatio, который напрямую задает размер пропускной способности.

9.4 Старые серийные номера

  • Версия сборщика Serial старого поколения, однопоточный алгоритм маркировки и сопоставления.
  • Обычно используется для виртуальных машин в режиме клиента.
  • Когда виртуальная машина находится в режиме сервера, ее можно использовать двумя способами: одно — использовать с коллектором Parallel Scavenge в JDK 1.5 и более ранних версиях, а другое — в качестве плана резервного копирования для сборщика CMS, когда происходит параллельный сбор. Сбой режима.

9.5 Параллельный старый

  • Старая версия сборщика Parallel Scavenge, использующая многопоточность и алгоритм пометки и очистки. Доступно в JDK 1.6. Используйте с коллекторами Parallel Scavenge, где важна пропускная способность.

9.6, CMS (Concurrent Mark Sweep) (старый возраст)

  • Коллектор, целью которого является получение кратчайшего времени паузы сбора. Он подходит для программ, которым необходимо взаимодействовать с пользователями, а хорошая скорость отклика может улучшить взаимодействие с пользователем.
  • На основе алгоритма метки-развертки. Подходит в качестве коллектора старого поколения.
  • Процесс сбора делится на 4 этапа:
1、 初始标记(CMS initial mark):只是标记一下GC Roots能直接关联到的对象,速度很快,会Stop The World。
2、 并发标记(CMS concurrent mark):进行GC Roots Tracing(可达性分析)的过程。
3、 重新标记(CMS remark):会Stop The -World。为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般比初始标记阶段稍长些,但远比并发标记的时间短。
4、 并发清除(CMS concurrent sweep):回收内存。

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

недостаток:

  • На параллельном этапе, хотя пользовательский поток и не будет приостановлен, он будет занимать часть потока (ресурс ЦП), что приведет к замедлению работы приложения и уменьшению пропускной способности. Количество запускаемых потоков сбора по умолчанию равно (количество ЦП + 3)/4. То есть при количестве ЦП больше 4 поток сборки мусора будет занимать не менее 25% ресурсов ЦП при параллельной сборке, и будет уменьшаться по мере увеличения числа ЦП. Но когда ЦП меньше 4 (например, 2), влияние CMS на пользовательскую программу может стать очень большим.
  • Невозможно очистить плавающий мусор. На этапе параллельной очистки пользовательский поток все еще работает, и создается новый мусор. Этот мусор не будет помечен в этом сборщике мусора и может только ждать, пока не будет собран следующий сборщик мусора.
  • Алгоритм маркировки-очистки будет генерировать большой объем прерывистой памяти, что приведет к нехватке памяти при выделении больших объектов, заранее запуская полный сборщик мусора.

9.7 G1

  • Расширенный сборщик мусора, представленный в JDK1.7.
  • Подходит как для молодых, так и для старых.
  • Консолидация пространства: используйте алгоритм маркировки для сортировки, который не создает фрагментированного пространства.
  • Вся куча Java разделена на регионы одинакового размера. Молодое поколение и старое поколение уже не изолированы физически, а представляют собой совокупность части блоков региона.
  • По умолчанию куча равномерно разделена на 2048 регионов, минимум 1M и максимум 32M, что должно быть степенью 2, которую можно передать через-XX:G1HeapRegionSizeспецификация параметра. Существует 4 типа регионов:
E:eden区,新生代
S:survivor区,新生代
O:old区,老年代
H:humongous区,用来放大对象。当新建对象大小超过region大小一半时,直接在新的一个或多个连续region中分配,并标记为H
  • Предсказуемое время паузы: оцените пространство для восстановления мусора в каждом регионе и время, необходимое для повторного использования (эмпирическое значение), записанное в списке приоритетов. При сборе сначала собирается регион с наибольшим значением, а не вся коллекция регионов всей кучи. Это повышает эффективность переработки, отсюда и название: Garbage-First. В G1 есть 2 вида GC:

  • молодой GC: срабатывает, когда в райской области нового поколения недостаточно свободного места. Выжившие объекты перемещаются в область выживших или перемещаются в старую область. Смешанный сборщик мусора: когда в старой области много объектов, отношение пространства объектов старого поколения к общему пространству кучи достигает порогового значения (-XX:InitiatingHeapOccupancyPercent по умолчанию равно 45%) и срабатывает.Он не только перерабатывает новое поколение , но и перерабатывает часть старой генерации (те, что с высоким коэффициентом извлечения) часть региона).

смешанные шаги восстановления GC:

1、初始标记(Initial Marking):只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark 2、Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象。这阶段需要停顿线程(STW),但耗时很短,共用YGC的停顿,所以一般伴随着YGC发生。
3、并发标记(Concurrent Marking):进行可达性分析,找出存活对象,耗时长,但可与用户线程并发执行。
4、最终标记(Final Marking):修正并发标记阶段用户线程运行导致的变动记录。会STW,但可以并行执行,时间不会很长。
5、筛选回收(Live Data Counting and Evacuation):根据每个region的回收价值和回收成本排序,根据用户配置的GC停顿时间开始回收。
  • Когда объект выделяется слишком быстро и у смешанного GC нет времени на переработку, G1 вырождается, вызывая полный GC, который использует однопоточный сборщик Serial для перезаписи.Всего процесса STW следует избегать, насколько это возможно.
  • Когда памяти мало (живые объекты занимают много места), не хватает места для копирования объектов, что приведет к сбою коллекции. В это время объекты, которые были перемещены, и объекты, которые не были перемещены, сохраняются, и корректируется только ссылка. После возникновения сбоя сборщик считает, что живой объект перемещен и места для использования приложением достаточно, поэтому пользовательский поток продолжает работать, ожидая следующего триггера GC. Если памяти недостаточно, будет запущена полная сборка мусора.

9.8. ЗГК

В JDK 11 был добавлен экспериментальный ZGC. В среднем на переработку уходит менее 2 миллисекунд. Это сборщик с низкой паузой и высокой степенью параллелизма.

ZGC исполняется одновременно практически везде, за исключением того, что начальная отметка STW. Так что время паузы практически тратится на начальную отметку, которой на самом деле очень мало. Так как же другие этапы могут выполняться одновременно?

ZGC в основном добавляет две новые технологии,

  • Цветная указка Цветная указка,
  • Прочтите «Барьерная нагрузка».

ZGC - это并发、基于区域(region)、增量式压缩коллекционер. Этап Stop-The-World происходит только на этапе корневого сканирования, поэтому время паузы GC не увеличивается с увеличением количества кучи и живых объектов.

Стадия обработки:

  • Маркировка;
  • Перемещение/уплотнение;
  • выбор набора релокации;
  • обработка ссылок;
  • Очистка слабых ссылок (WeakRefs Cleaning);
  • очистка пула строковых констант (String Table) и таблицы символов (Symbol Table);
  • Разгрузка класса

Цветной указатель

ZGC利用指针的64位中的几位表示Finalizable、Remapped、Marked1、Marked0(ZGC仅支持64位平台),以标记该指向内存的存储状态。
相当于在对象的指针上标注了对象的信息。注意,这里的指针相当于Java术语当中的引用。

在这个被指向的内存发生变化的时候(内存在Compact被移动时),颜色就会发生变化。

Прочитать Барьер Загрузить Барьер

由于着色指针的存在,在程序运行时访问对象的时候,可以轻易知道对象在内存的存储状态(通过指针访问对象),
若请求读的内存在被着色了,那么则会触发读屏障。读屏障会更新指针再返回结果,此过程有一定的耗费,从而达到与用户线程并发的效果。

По сравнению с традиционным алгоритмом маркировки объектов ZGC маркирует указатель и добавляет Load Barrier (барьер чтения) при доступе к указателю.Например, когда объект перемещается GC, цвет указателя будет неправильным, и этот барьер сначала обновит указатель до эффективного адреса, а затем вернет, то есть всегда есть вероятность, что только один объект будет тормозить при чтении, и нет Stop The World, чтобы сохранить согласованность приложения с ГК.

расширять

Java — семь сборщиков мусора + JDK11 последний ZGC

Категории