Что такое JVM.
JVM, виртуальная машина Java, представляет собой абстрактный компьютер с набором инструкций, который управляет различными областями памяти во время выполнения. Существует много типов виртуальных машин, и разные производители предоставляют разные реализации, если они соответствуют спецификациям виртуальных машин.В настоящее время виртуальная машина, о которой мы говорим, обычно относится к Hot Spot. JVM ничего не знает о языке Java и знает только определенный двоичный формат, а именно формат файла класса.Когда написанная нами программа будет наконец передана JVM для выполнения, она будет скомпилирована в двоичный формат.Только JVM знает двоичный формат, поэтому любой. Если скомпилированный формат соответствует требованиям, язык можно запускать на JVM.
После того, как класс Java скомпилирован и загружен, он помещает загруженные данные в область данных времени выполнения, чтобы мы могли напрямую считывать информацию из области данных времени выполнения при запуске программы.
Область текущих данных
счетчик команд
Счетчик программ — это пространство, доступное только потоку. Виртуальная машина Java может выполнять несколько потоков одновременно, но в любой момент процессор может выполнять только одну инструкцию в одном потоке, а поскольку потоки случайны, операционная система всегда будет переключаться на выполнение разных инструкций, нам нужно put При переключении позиция выполнения потока сохраняется в регистре ПК, а при обратном переключении он может вернуться в исходное положение для продолжения выполнения. В любое время каждая виртуальная машина Java выполняет код для одного метода, текущего метода для этого потока. Если метод не является нативным, то есть в регистр ПК будет записан адрес выполняемой в данный момент инструкции виртуальной машины Java.Если метод, исполняемый в данный момент потоком, является локальным, то значение регистра ПК виртуальной машина не определена. Счетчик программ — единственная область, в которой не возникает OOM.
куча
Куча — это самый большой участок памяти, управляемый виртуальной машиной Java. Он создается при запуске виртуальной машины и используется всеми потоками. Объекты в куче никогда не освобождаются явным образом и должны быть освобождены сборщиком мусора. GC также в основном перерабатывает экземпляры объектов в куче Мы обычно обсуждаем сборку мусора для освобождения памяти кучи. Куча может находиться в физически прерывистом пространстве, с фиксированным размером или динамическим расширением Минимальное и максимальное значения кучи контролируются параметрами -Xms и -Xmx.
область метода
Область методов также является областью, совместно используемой потоками, которая создается при запуске виртуальной машины и хранит структуру каждого класса, такую как: пул констант времени выполнения, данные свойств и методов, а также код метода и конструктора, в том числе в инициализации класса и экземпляра. и интерфейс Специальный метод, используемый для инициализации.Область метода логически является частью кучи, но у нее есть еще один псевдоним, называемый не-кучей, который предназначен для отделения от кучи. Область метода может иметь фиксированный размер или может быть расширена в соответствии с вычислительными потребностями. OutOfMemoryError также генерируется, если память в области метода не может удовлетворить запрос на выделение.
постоянный пул времени выполнения
Часть области методов, используемая для хранения скомпилированных литералов (базовые типы данных или константы или строки, измененные с помощью final) и символических ссылок.Пул констант времени выполнения класса или интерфейса создается, когда виртуальная машина Java создает класс или интерфейс. из.В jdk1.6 и более ранних версиях строки в Java помещаются в пул констант времени выполнения в области методов, но после jdk1.7 пул строковых констант извлекается и помещается в кучу.
public class GcDemo {
public static void main(String [] args) {
String str = new String("lonely")+new String("wolf");
System.out.println(str == str.intern());
}
}
Этот код выводит false в jdk1.6 и true в jdk1.7 и jdk1.8. О методе intern():
- jdk1.6: при вызове метода String.intern() он сначала проверяет, существует ли строка в пуле констант, если она не существует, в области метода будет создана строка, а строка создается новой строкой () будет в куче, адреса двух строк конечно не равны.
- jsk1.8: пул строковых констант перемещается из пула констант времени выполнения в области методов в кучу. При вызове метода String.intern() он сначала проверяет, существует ли пул констант. Если он не существует, будет создана константа и задано значение Ссылка указывает на кучу, что означает, что строковый объект не будет воссоздан, оба будут указывать на объекты в куче, поэтому верните true.
интересный пример
- Существует только одна новая String(), которая создает два объекта.
public class GcDemo {
public static void main(String [] args) {
String str = new String("lonely");
System.out.println(str == str.intern());
}
}
Существует только одна новая String(), которая также вернет false в jdk1.7 и jdk1.8.Мы предполагаем, что сначала в пуле строковых констант нет строк, и выполнение новой строки("одинокой") будет генерировать два объекта, один в куче, один в пуле строковых констант.
В это время String.intern() сначала проверяет пул строковых констант и обнаруживает, что есть «одинокая» строка, поэтому возвращается напрямую.В это время два адреса различны, поэтому возвращается false.
- new String("lonely")+new String("wolf") сгенерирует 5 объектов, 2 в пуле строковых констант и 3 в куче.
В настоящее время, если выполняется String.intern(), пул строковых констант будет проверен в версиях 1.7 и 1.8, а строки одинокого волка нет, поэтому в пуле строковых констант будет создана одна строка, указывающая на строку в куче. .
Однако в jdk1.6 он не будет указывать на кучу, и строка одинокого волка будет воссоздана и помещена в пул строковых констант, поэтому будут получены другие результаты.
Разница между областью методов реализации jdk1.7 и jdk1.8
- До jdk1.7 область метода была реализована с использованием постоянной генерации.Размер области метода можно контролировать с помощью параметров -XX:PermSize и -XX:MaxPermSize для управления размером области метода и максимально допустимым значением.
- Постоянные поколения jdk1.8 удалены, реализованы с использованием пространства элементов, поэтому параметры генерации jdk1.8 навсегда изменены -XX: MetaspaceSize и -XX: MaxMetaspaceSize. Большое разностное пространство и постоянное пространство от имени юаня больше не находится в JVM, память непосредственно в локальной памяти.
стек виртуальных машин
Стек виртуальной машины — это уникальное пространство для потоков, и каждый поток имеет собственный стек виртуальной машины, созданный одновременно с потоком. Кадр стека хранится в стеке виртуальной машины.Каждый метод, вызываемый потоком, создает кадр стека.Кадр стека сохраняет информацию о состоянии метода, такую как локальные переменные, кадры операндов и выходы метода. Вызов метода — это процесс выполнения фрейма стека.По завершении вызова метода соответствующий фрейм стека выталкивается из стека.
Стек виртуальной машины может иметь следующие два исключения:
- Если глубина стека, необходимая для выполнения потока, больше, чем глубина стека виртуальной машины Java, будет выброшено сообщение StackOverFlowError.Фактически, процесс вызова метода представляет собой процесс помещения и извлечения стека.Если стек последовательно помещается в стек и вне стека могут возникать исключения (рекурсивные вызовы).
- Если стек виртуальной машины Java может быть динамически расширен, но не может запросить достаточно памяти при увеличении размера, будет выдан OutOfMemoryError.
Стек собственных методов
Локальный стек метода аналогичен стеке виртуальной машины. Разница состоит в том, что локальный метод стека хранит нативные методы. Метонный метод стека и стек виртуальной машины объединяются в некоторых виртуальных машинах, таких как виртуальная машина для горячей точки.
исключение памяти
переполнение памяти
концепция
Памяти JVM не хватает, и созданный объект в данный момент не может быть сохранен
причина
- Память, выделенная JVM, слишком мала, или сам сервер может быть слишком мал, или память кучи, выделенная JVM, слишком мала
- Определенный фрагмент кода находится в бесконечном цикле, что приводит к созданию сумасшедших объектов, но не запускает GC.
- Созданный объект слишком велик, так что новое поколение не может выжить, а старое поколение не может выжить, поэтому он может быть только OOM.
решать
- Увеличьте память сервера, установите разумные -Xms и -Xmx
- Анализ проблемного кода с помощью дампа потока и дампа кучи
- Увеличение памяти JVM, своевременный GC
утечка памяти
концепция
Объект не должен использоваться не переработано, это утечка памяти
пример
public class Simple{
Object o1;
public void method() {
o1 = new Object();
//...其他代码
}
}
在Simple实例被回收之前,o1都不会被回收,因为o1是全局变量
Улучшать:
public class Simple{
Object o1;
public void method() {
o1 = new Object();
//...其他代码
o1 = null; //帮助GC
}
}
Модель объектной памяти
объект, указывающий
package com.zwx.jvm;
public class HeapMemory {
private Object obj1 = new Object();
public static void main(String[] args) {
Object obj2 = new Object();
}
}
Мы знаем, что obj1 — это атрибут класса, на который ссылается область методов, а obj2 — это локальная переменная, которая ссылается на таблицу локальных переменных, хранящуюся во фрейме стека в стеке виртуальной машины. Итак, obj1 — это область методов, указывающая на кучу, а obj2 — классический стек виртуальной машины, указывающий на кучу. obj1 — это область метода, указывающая на кучу:
obj2 — это куча, на которую указывает стек виртуальной машины:
Давайте подумаем над вопросом. Переменная указывает на кучу, а куча хранит только экземпляр объекта. Как она узнает, к какому классу он принадлежит, то есть как этот экземпляр узнает соответствующую метаинформацию класса? Это включает в себя структуру памяти объекта Java.
новые объекты занимают несколько байтов
Память объекта разделена на три блока: заголовок объекта (Header), данные экземпляра (Instance Data) и заполнение выравнивания. Взяв в качестве примера 64-битную операционную систему (без включения сжатия указателя), макет объекта Java выглядит следующим образом:
Заполнение выравнивания не обязательно требуется.Если заголовок объекта + данные экземпляра являются целым числом, кратным 8, заполнение выравнивания не требуется.
Размер Object obj = new Object() можно разделить на два случая:
- Сжатие указателя не включено: занимаемый размер = 8 байтов Mark Word + 8 байтов указателя класса = 16 байтов
- Сжатие указателя включено: занимаемый размер = 8 байтов слова метки + 4 байта указателя класса + 4 байта заполнения выравнивания = 16 байтов.
Давайте проверим: 1. Введите pom-зависимости
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
2, новая демо
public class HeapMemory {
public static void main(String [] args) {
Object obj = new Object();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
Результатом является 16 байтов = 8 байтов слова метки + 4 байта указателя класса + 4 байта указателя класса + 4 байта, так как по умолчанию включено сжатие указателя.
-XX:+UseCompressedOops 开启指针压缩
-Xx:-UseCompressedOops 关闭指针压缩
Ниже мы вручную отключаем сжатие указателя
Результат повторного запуска:
Вы можете видеть, что 16 байтов = 8 байтов Mark Word + 8 байтов указателя класса на данный момент.
Два способа доступа к объектам
обрабатывать доступ
Используя доступ к дескриптору, виртуальная машина Java делит часть памяти в куче для хранения пула дескрипторов, затем адрес дескриптора сохраняется в ссылке на объект, а данные экземпляра объекта и адрес данных типа объекта сохраняются в обрабатывать бассейн.
прямой доступ по указателю
Прямой доступ к указателю, ссылка на объект напрямую указывает на данные экземпляра объекта
Сравнение двух способов
Использование доступа к дескриптору приведет к еще одному позиционированию указателя, но у него также есть то преимущество, что если объект перемещается (меняется адрес), вам нужно только изменить указатель пула дескрипторов, и вам не нужно изменять указатель в пуле дескрипторов. Если вы используете прямой доступ по указателю, вам необходимо изменить точку отсчета в таблице локальных переменных.
целевой возраст
Возраст поколения
Возраст генерации объекта можно понимать как количество сборок мусора. Когда объект все еще существует после сборки мусора, возраст генерации равен +1. В 64-битной операционной системе возраст генерации занимает 4 цифры, максимальное значение равно 15 (1111), а возраст генерации по умолчанию равен 0000, который постепенно увеличивается с количеством сборок мусора. Ява разделена на Молодую область и Старую область в соответствии с возрастом поколения.Объекты обычно сначала попадают в Молодую область, а затем по достижении определенного возраста входят в Старую область (Примечание: большие объекты напрямую попадают в Старую область). Причина такого деления в том, что если во всей куче всего одна область, то при сборке мусора нужно сканировать все объекты, что приводит к потере производительности. На самом деле жизненный цикл большинства Java-объектов очень короткий: если объект не может быть повторно использован много раз, можно считать, что следующая переработка не может быть переработана, поэтому область «Молодая» и область «Старая» могут быть переработаны отдельно. Сборка мусора в Старой зоне срабатывает только тогда, когда после сборки не хватает места в Молодой зоне.
Молодой район
Теперь он разделен на область Юнга, следующая область Юнга после сборки мусора:
Если есть объект, который занимает размер двух объектов, будет обнаружено, что он не может быть положен вниз, и в это время будет запущен GC, но как только GC будет запущен, он повлияет на пользовательский поток, потому что процесс GC должен гарантировать, что ссылка на объект остается неизменной.Остановите все пользовательские потоки, этот процесс называется STW: Stop The World. Таким образом, в целом, чем меньше GC, тем лучше.На самом деле, на приведенном выше рисунке можно поместить как минимум три объекта.Однако из-за разрыва пространства объект не может примениться к памяти и вызывает GC.Как решить Эта проблема?
Решение состоит в том, чтобы разделить область Молодых на две области: область Эдема и область Выживших.
Конкретная операция: после прибытия объекта он сначала размещается в области Эдема.После заполнения области Эдема запускается GC.После GC, чтобы предотвратить разрыв пространства, уцелевшие объекты копируются в область Survivor, а затем за один раз очищается область Эдема (предпосылка этого заключается в том, что у большинства объектов очень короткий жизненный цикл, а область Эдема может быть утилизирована в основном одной сборкой мусора). При срабатывании ГК область Выжившего также будет перерабатываться вместе.Это не значит, что только область Эдема срабатывает одна, но проблема грядет.Область Эдема гарантирует, что пространство в основном непрерывное, но Выживший может генерировать космический мусор, что приводит к разрыву. Зона Survivor разделена на две части:
Общий процесс таков: когда объект приходит, сначала выделяем память в области Eden, запускаем GC после заполнения Eden, назначаем уцелевшие объекты в область S0 после GC (область S1 пуста), а затем продолжаем выделять объектов в районе Эдема, После повторного срабатывания GC, если обнаружится, что S0 не может быть установлен (происходит фрагментация пространства, на самом деле еще есть место), то скопируйте уцелевшие объекты из S0 в S1. Область S0 пуста, и операции повторяются по очереди. Если космические объекты в области S0 и области S1 не могут быть размещены после копирования и перемещения, это означает, что она действительно заполнена, тогда перейдите к старости, чтобы занять немного места (это гарантийный механизм, старости нужно предоставить такую гарантию распределения пространства), если в старом возрасте Если пространства эпохи недостаточно, будет запущен полный сборщик мусора, а если его все еще недостаточно, будет выброшен OutOfMemoryError.
Старый район
Когда объект в молодой области достигнет установленного возраста генерации, объект войдет в старую область.Когда старая область будет заполнена, будет запущен полный Gc.Если места все еще недостаточно, произойдет OOM.
жизненный цикл объекта
При нормальных обстоятельствах объекты будут перемещаться между областью Эдема, областью S0, областью S1 и старой областью.
механизм загрузки классов
файл класса
Введение
В Java каждый файл класса содержит один класс или интерфейс, и каждый файл класса состоит из потока 8-битных байтов. Все 16-битные, 32-битные и 64-битные величины создаются путем чтения 2, 4 и 8 байтов соответственно. Виртуальная машина Java предусматривает, что формат файла класса использует для хранения данных псевдоструктуру, аналогичную языку C. В файле класса есть только два типа данных: числа без знака и таблицы. Примечание: файл класса не имеет заполнения выравнивания, все данные компактно расположены в файле класса в определенном порядке.
- Беззнаковое число: относится к базовому типу данных, где u1, u2, u4, u8 представляют 1, 2, 4 и 8 байтов.
- Таблица: 0 или множество элементов, состоящих из переменного размера, множество файловой структуры класса, что класс эквивалентен таблице фактов.
структура
Файл класса примерно имеет следующую структуру:
ClassFile {
u4 magic;//魔数
u2 minor_version;//次版本号
u2 major_version;//主版本号
u2 constant_pool_count;//常量池数量
cp_info constant_pool[constant_pool_count-1];//常量池信息
u2 access_flags;//访问标志
u2 this_class;//类索引
u2 super_class;//父类索引
u2 interfaces_count;//接口数(2位,所以一个类最多65535个接口)
u2 interfaces[interfaces_count];//接口索引
u2 fields_count;//字段数
field_info fields[fields_count];//字段表集合
u2 methods_count;//方法数
method_info methods[methods_count];//方法集合
u2 attributes_count;//属性数
attribute_info attributes[attributes_count];//属性表集合
}
Мы произвольно пишем файл TestClassFormat.java
public class TestClassFormat {
public static void main(String[] args) {
System.out.println("Hello JVM");
}
}
Поскольку виртуальная машина Java распознает только файлы классов, она обязана выполнять строгую проверку безопасности в отношении формата файлов классов.
Обзор
После компиляции файла .java файл класса необходимо загрузить в память, а данные сохраняются в области данных времени выполнения в соответствии с классификацией. Класс пройдет 5 шагов (7 этапов) от загрузки в память до выгрузки после использования: Загрузка->Подключение->Инициализация->Использование->Выгрузка. Соединение делится на проверку, подготовку и разбор.
нагрузка
Загрузка относится к получению формы его двоичного потока через полное имя класса или интерфейса и сохранению данных в области данных времени выполнения в соответствии со спецификацией виртуальной машины Java Загрузка класса в основном выполняет три функции:
- Получает поток двоичных байтов, определяющих класс по его полному имени.
- Преобразует статическое хранилище, представленное этим двоичным потоком байтов, в структуру данных времени выполнения области метода.
- Объект java.lang.Class, представляющий этот класс, создается в куче Java как запись доступа к этим данным в области методов.
Первый шаг выше не объясняет, откуда берется класс или как его получить в спецификации виртуальной машины, поэтому будет много реализаций. Ниже приведены некоторые часто используемые реализации:
- Самый нормальный способ: прочитать локальный скомпилированный файл .class
- , jar, war как прочитано из архива zip.
- читать из сети
- Динамически генерировать файлы .class через динамические прокси
- читать из базы данных
Загрузчик классов требуется для выполнения загрузки класса, а квалифицированный загрузчик классов должен иметь следующие два свойства:
- Один и тот же объект класса всегда должен возвращаться для одного и того же имени класса.
- Если загрузчик класса L1 делегирует загрузчику класса L2 загрузку объекта класса C, то для любого типа T в следующих сценариях оба загрузчика классов L1 и L2 должны возвращать один и тот же объект Class:
(1) Прямой родительский класс или тип родительского интерфейса C
Тип поля (2) C в
(3) Типы параметров методов или конструкторов в C
(4) Тип возвращаемого значения метода в C
В Java существует более одного загрузчика классов.Объекты, загруженные разными загрузчиками классов для одного и того же класса, не равны.Так как же Java гарантирует выполнение двух вышеуказанных пунктов? Это модель родительского делегирования.Java использует модель родительского делегирования для предотвращения вредоносной загрузки и обеспечения безопасности.
Модель родительского делегирования
Обзор
Определение: когда классный загрузчик для загрузки квитанции о загрузке запроса вы не переходите к загрузке, но к его родительскому загрузке нагрузки и т. Д. Этот класс, подгрузчик попытается загрузить класс.
На приведенном выше рисунке показана модель родительского делегирования. Загрузчик верхнего уровня использует пунктирную линию, чтобы указать, что загрузчик верхнего уровня не имеет родительского загрузчика. С точки зрения реализации дочерний загрузчик отсутствует. Это независимый загрузчик, поскольку расширение загрузчик класса и загрузчик приложения.С точки зрения отношения наследования существует отношение родитель-потомок, и оба наследуют URLClassLoader, но хотя загрузчик класса запускается из отношения наследования класса и не имеет дочернего загрузчика, логически расширяя класс загрузчик по-прежнему будет отдавать приоритет полученному запросу.Упреждающая загрузка для загрузчика класса запуска.
- Загрузчик классов запуска: отвечает за загрузку классов в каталоге $JAVA_HOME\lib или классов, указанных параметром -Xbootclasspath, которые могут быть распознаны виртуальной машиной (идентифицируемой по имени jar, например rt.jar). Загрузчик классов запуска — это непосредственно управляется виртуальной машиной Java, разработчик не может напрямую использовать загрузчик классов запуска.
- Расширенный загрузчик классов: отвечает за загрузку классов в $JAVA_HOME\lib\ext или всех библиотек классов по пути, указанному в системной переменной java.ext.dirs. Разработчики могут использовать этот загрузчик классов напрямую.
- Загрузчик классов приложения: отвечает за загрузку библиотеки классов, указанной в $CLASS_PATH. Разработчики могут использовать этот загрузчик классов напрямую. Обычно, если у нас нет собственного загрузчика классов в приложении, обычно используется этот загрузчик классов.
- Пользовательский загрузчик классов: при необходимости вы можете определить свой собственный загрузчик классов через подкласс java.lang.ClassLoader.Как правило, мы выбираем наследуемый URLClassLoader, чтобы переписать его соответствующим образом.
Разбивая модель родительской делегации
Модель родительского делегирования является не обязательной моделью ограничений, а рекомендуемой моделью загрузки, и некоторые из них не соответствуют этой модели: например, связанные действия SPI, такие как JNDI, JDBC и т. д., не полностью соответствуют родительской модели делегирования, что разрушает модель родительского делегирования.Самый простой способ: унаследовать класс ClassLoader, а затем переписать в нем метод loadClass (т.к. логика родительского делегирования находится в методе loadClass)
Общее исключение
Если во время загрузки возникает исключение, может быть выдано следующее исключение
- ClassCircularityError: расширяет или реализует собственный класс или интерфейс.
- ClassFormatError: неправильный двоичный формат для класса или интерфейса
- NoClassDefFoundError: не удалось найти соответствующий класс или интерфейс на основе предоставленного полного имени.
ClassNotFoundException и NoClassDefFoundError
- ClassNotFoundException: это исключение возникает, когда JVM хочет загрузить байт-код указанного файла в память и обнаруживает, что файл не существует. Это исключение обычно возникает при явной загрузке, в основном в следующих трех сценариях:
(1) Вызов Class.forName() (2) Вызовите метод findSystemClass() ClassLoader (3) Вызовите метод loadClass() ClassLoader Решение: Вручную проверьте, есть ли этот файл в пути к классам.
- NoClassDefFoundError: это исключение обычно возникает при неявной загрузке.Может использоваться ключевое слово new, или атрибут относится к классу, или он наследует класс или интерфейс, или параметр в методе относится к определенному классу, который инициирует неявную загрузку JVM. в это время, и если класс не существует во время процесса загрузки, будет выдана эта ошибка.
Обходной путь: убедитесь, что каждый класс, на который ссылаются, находится в текущем пути к классам.
соединять
Связывание: процесс получения двоичной формы класса или интерфейса и включения его в состояние выполнения виртуальной машины Java для выполнения. Подключение состоит из трех этапов: проверка, подготовка и разбор.
проверять
Загрузка класса требует проверки формата для проверки следующих аспектов:
- Проверка формата файла: например, начинается ли он с магического числа, правильность номера версии jdk и т. д.
- Проверка метаданных: например, допустимы ли поля в классе, существует ли родительский класс, является ли родительский класс допустимым и т. д.
- Проверка байт-кода: в основном для определения логичности семантики и потока управления программы.
Если проверка не удалась, выдается VerifyError.
Подготовить
Подготовка: Формально начинается фаза выделения адресов памяти, в основном создание статических полей (константы и константы класса) для класса или интерфейса и инициализация этих полей значениями по умолчанию. Предполагая, что эти поля уже существуют в пуле констант, назначьте их напрямую.
static final int i=100;
Этот вид окончательной модификации будет напрямую назначить начальное значение, а не значение по умолчанию. Ниже приведены следующие значения по умолчанию:
Разобрать
Решение: Процесс замены символических ссылок в пуле констант прямыми ссылками. Прежде чем можно будет использовать символическую ссылку, она должна быть проанализирована, во время которой проверяется правильность символической ссылки.
инициализация
Этот этап является присваиванием, которое заменит ранее назначенное значение по умолчанию реальным начальным значением.Этот шаг также выполняется при выполнении конструктора. Когда его нужно инициализировать? Каков порядок инициализации родительского и дочернего классов? Спецификация виртуальной машины Java предусматривает, что класс должен быть инициализирован в пяти случаях, а поведение активного запуска инициализации называется активной ссылкой:
- При запуске виртуальной машины сначала инициализируйте указанный основной класс, который необходимо выполнить (класс, в котором находится основной метод)
- При создании экземпляра объекта с ключевым словом new считывайте или устанавливайте статические поля класса (кроме полей, измененных с помощью final) и вызывайте статические методы класса.
- Инициализация класса, если не инициализируется родительский класс, чтобы инициировать инициализацию родительского класса (разные интерфейсы, при инициализации интерфейса родителю не требуется инициализация интерфейса)
- При вызове класса с использованием отражения
- Когда JDK1.7 обеспечивает поддержку динамического языка, если класс, соответствующий дескриптору метода REF_getStatic, REF_putStatic и REF_invokeStatic в результате синтаксического анализа экземпляра java.lang.invoke.MethodHandler, не инициализирован, его инициализацию необходимо инициировать.
public class TestInit1 {
public static void main(String[] args) {
System.out.println(new SubClass());//A-先初始化父类,后初始化子类
// System.out.println(SubClass.value);//B-只初始化父类,因为对于static字段,只会初始化字段所在类
// System.out.println(SubClass.finalValue);//C-不会初始化任何类,final修饰的数据初始化之前就会放到常量池
// System.out.println(SubClass.s1);//D-不会初始化任何类,final修饰的数据初始化之前就会放到常量池
// SubClass[] arr = new SubClass[5];//E-数组不会触发初始化
}
}
class SuperClass{
static {
System.out.println("Init SuperClass");
}
static int value = 100;
final static int finalValue = 200;
final static String s1 = "Hello JVM";
}
class SubClass extends SuperClass{
static {
System.out.println("Init SubClass");
}
}
- Заявление о выходе:
Init SuperClass Init SubClass com.zwx.jvm.SubClass@xxxxxx
- Выходной результат оператора B: (Хотя статическая переменная вызываемого класса вызывается подклассом, статическая переменная относится к родительскому классу, поэтому запускается только инициализация родительского класса, поскольку вызов статической переменной вызовет только класс, в котором находится атрибут. )
Init SuperClass 100
- Вывод оператора C и оператора D:
200
Hello JVM
Поскольку статическая переменная, измененная с помощью final, уже существует в пуле констант, она была назначена на этапе подготовки соединения, и нет необходимости инициализировать класс.
- E Заявление не выводится никакого результата, поскольку объект массива конфигурации и настраиваемый для прямого направления объекта достигается с помощью различных инструкций по байтовым кодам, созданным одним массивом, достигается инструкцией NewArray, и не инициализирует объект.
использовать
После вышеперечисленных 5 шагов в память загружается готовый объект, после чего мы можем использовать его непосредственно в коде.
удалить
Когда объект больше не используется, он удаляется сборщиком мусора.
Проверить, подлежит ли объект вторичной переработке
Первое, что нужно знать о сборке мусора, — как определить, подлежит ли объект переработке (является ли он мусором). Основной метод: подсчет ссылок/анализ достижимости.
Отсчет ссылки
Этот алгоритм прост и эффективен. Он заключается в добавлении к объекту счетчика ссылок. Когда место ссылается на него, он увеличивается на 1. Когда ссылка недействительна, он уменьшается на 1. Когда значение счетчика равно 0 , это означает, что объект не будет использоваться и станет бесполезным объектом. , может быть переработан. Хотя этот алгоритм прост, у него есть фатальная проблема: он не может решить проблему взаимных ссылок.
Вышеупомянутые четыре объекта ссылаются друг на друга, но никакие другие объекты не ссылаются на них.Такие объекты на самом деле являются недействительными объектами, но их значение счетчика равно 1 и не может быть повторно использовано методом подсчета ссылок.
Анализ доступности
Метод анализа достижимости состоит в том, чтобы выбрать некоторые объекты, называемые корнями GC, в качестве отправной точки, а затем начать поиск вниз от корней GC. Путь поиска называется цепочкой ссылок. Когда объект не находится ни в одной цепочке ссылок, это означает, что объект недействителен объекты могут быть переработаны. Анализ достижимости решает проблему взаимной ссылки между объектами в методе подсчета ссылок.
Какие объекты можно использовать в качестве корней GC?
- Переменные кадра стека в таблице локальных переменных в стеке виртуальной машины Java
- Статические свойства класса зоны метода
- Константы в области методов
- Переменные в стеке собственного метода JNI (т.е. собственный метод)
Четыре категории цитат
Сильная ссылка > Мягкая ссылка > Слабая ссылка > Фантомная ссылка
сильная цитата
Код, который мы пишем, обычно является строгой ссылкой. Например, Object obj = new Object() является строгой ссылкой. Если сильная ссылка все еще существует, она не будет переработана. Если места недостаточно, OOM будет выбран напрямую .
мягкая ссылка
Мягкие ссылки реализованы классом SoftReference. Мягкие ссылки используются для представления некоторых полезных, но ненужных объектов. Прежде чем система переполнится, если она обнаружит, что есть объекты с мягкими ссылками, они будут утилизированы дважды. После восстановления памяти все равно не хватает.выкинет OOM
слабая ссылка
Слабые ссылки реализуются через WeakRerefence. Слабые ссылки также используются для представления несущественных объектов, но по сравнению с мягкими ссылками объекты со слабыми ссылками будут утилизированы во время первой сборки мусора.
фантомная ссылка
Виртуальная ссылка реализована с помощью PhantomReference, которая называется фантомной ссылкой или фантомной ссылкой, самой слабой ссылкой. Наличие у объекта виртуальной ссылки не влияет на время его жизни, и экземпляр объекта не может быть получен через виртуальную ссылку. Единственная польза от установки фантомной ссылки — получение системного уведомления при восстановлении объекта.
Алгоритм сборки мусора
Когда определено, что объект должен быть переработан, происходит следующий процесс переработки, и переработка имеет разные алгоритмы.
алгоритм маркировки-развертки
Перед утилизацией
1. Просканируйте память кучи, а затем отметьте объекты серой области
2. Продолжайте сканирование, при сканировании отмеченные объекты будут равномерно перерабатываться.
После переработки:
Видно, что пространство памяти после повторного использования является прерывистым, что приводит к фрагментации памяти.
недостаток:
- И маркировка, и очистка неэффективны.
- Генерирует большое количество прерывистых фрагментов памяти
алгоритм репликации
Идея алгоритма копирования состоит в том, чтобы разделить область памяти на две части, две части памяти имеют одинаковый размер, и только одна из них используется одновременно, когда одна из них израсходована, уцелевшие объекты копируются в другие, а потом этот кусок памяти очищается за один раз.
Перед утилизацией:
После переработки:
Недостатком алгоритма копирования является то, что он жертвует половиной объема памяти, что немного расточительно. Вариант реализации алгоритма репликации в JVM таков: память кучи java была разделена несколько раз, соотношение Eden и Survivor в виртуальной машине Hot Spot равно Eden:S0:S1=8:1:1, а Survivor равно разделенный на две области S0 и S1, используется для назначения.Этот подход должен компенсировать потери исходного алгоритма копирования, напрямую используя половину пространства в качестве свободного пространства. IBM заявила: 98% объектов в области Янга мертвы, а жизненный цикл очень короткий, поэтому очень мало объектов выживают после GC, поэтому нет необходимости использовать половину пространства для копирования.
алгоритм маркировки-сопоставления
Тег-организатор - это алгоритм, разработанный для старческого, марк-организационного алгоритма и метки. Очистить отличие алгоритма на последнем шаге, маркировка-отделка не очищает объект напрямую, а перемещает, перемещает объект выживания в один конец, затем очищается объекты, отличные от границы. Перед утилизацией:
После переработки:
Алгоритм сбора поколений
В настоящее время основные коммерческие виртуальные машины используют алгоритм сбора индексов, который представляет собой комбинацию трех описанных выше алгоритмов. В новом поколении используется алгоритм репликации, в старческом — алгоритм метки — отделки или метки — очистки.
уборщик мусора
Сборщик мусора — это конкретная реализация алгоритма сборки мусора.Ниже приводится краткое описание сборщика мусора.
Серийный и серийные старые коллекторы
Последовательный сборщик является самым основным, первый сборщик. Последовательный сборщик — это один поток, то есть при GC STW (Stop The World) для приостановки всех пользовательских потоков, если время GC слишком велико, вы можете почувствовать Caton. Serial Old однопоточный, роль старой эпохи.
Преимущества: простой и эффективный, с высокой эффективностью однопоточной сборки.
Минусы: требуется STW, приостанавливает все пользовательские потоки
Алгоритм: Serial принимает алгоритм копирования, Serial Old использует алгоритм маркировки-сопоставления.
Коллекционер ParNew
ParNew — это многопоточная версия Serial, которая реализует параллельный сбор, принцип тот же, что и у Serial (параллельный относится к нескольким параллельным потокам GC, но пользовательские потоки по-прежнему приостановлены, а параллелизм относится к одновременному выполнению пользовательских потоков и нити GC). По умолчанию ParNew включает количество потоков, равное количеству процессоров для перезапуска.
Преимущества: в многопроцессорном режиме более эффективен, чем последовательный. Недостатки: по-прежнему требуется STW, который менее эффективен, чем последовательный, при использовании одного процессора. Алгоритм: Алгоритм копирования
Параллельный сборщик мусора
Сборщик нового поколения также является алгоритмом репликации. Это параллельный многопоточный коллектор, такой как Parnew. Он уделяет больше внимания пропускной способности системы (пропускная способность = (время для запуска пользовательского кода) / (время для запуска пользовательского кода + GC) Время)) Параллельный Scavange предоставляет два параметра для точного контроля пропускной способности:
-XX:MaxGCPauseMillis //GC最大停顿毫秒数,必须大于0
-XX:GCTimeRation //设置吞吐量大小,大于0小于100,默认值为99
Вы не будете чувствовать, что набор MaxGCPauseMillis, сделает небольшую скорость GC увеличиваться? Ответ не является, если установленное время слишком мало, параллельно Scavange за счет пропускной способности и новое поколение пространства для обмена, например, в течение всего времени новое поколение 400 МБ, требуется 100 мс, установлено на 50 мс, то он поместит Новое поколение небольших нот 200 МБ, на этот раз, безусловно, наверняка спускается, однако это может снизить пропускную способность исходных 10-х спусковых GC, каждые 100 мс, модифицированное время становится 5S Trigger A GC, каждые 70 мс, 10 мс, а затем триггер дважды GC Время стало 140 мс, но более низкая пропускная способность. По параметрам -xx: + UseAdaptiveizePolicy Открыть адаптивную стратегию, поэтому нам не нужно вручную установить виртуальную машину динамически регулируемой на основе условий эксплуатации.
Параллельный Старый коллектор
Это старая версия Parallel Scavange, потому что Parallel Scavange нельзя использовать с CMS, поэтому его можно использовать только с Serial Old. С момента появления Parallel Old существовала комбинация Parallel Scavange+Parallel Old, представляющая собой набор сборщиков, ориентированных на пропускную способность, используемую JDK1.8.
Сборщик CMS
Это сделано для оптимизации сборщика целей времени паузы GC, одновременного восстановления (все еще нужно STW, но времени очень мало). + UseMarkSweepGC включен: на -XX. CMS на основе алгоритма маркировки. Весь процесс делится на четыре этапа:
- Начальный тег: требуется STW, обозначающий объект GC Roots.
- Параллельная метка: этот этап может быть объединен в пользовательские потоки и разделен на три этапа:
(1) Начать поиск объектов, подключенных к корням GC в соответствии с корнями GC, найденных на первом шаге. (2) Предварительная очистка: этот этап - обработать объекты, которые изменились после одновременной маркировки. (3) Предоставленная предварительная очистка: на этом этапе будет условие триггера прерывания. Целью данного этапа - надеяться, что молодой GC может возникнуть, так что количество объектов в молодой области может быть уменьшено и рабочая нагрузка. Из повторной маркировки можно уменьшить. Маркировка сканирует все кучи пространства. Вы можете использовать параметр -xx: + CMSSCAVANGEBEFOREMEMARK для контроля возникновения молодого GC до замещения. По умолчанию False.
- Примечание: требуется STW, этот этап предназначен для исправления объектов, которые изменились после маркировки этапа 2.
- Параллельная очистка: Одновременно с пользовательским потоком он начинает формальную очистку мусора, а сгенерированный на этом этапе мусор оставляется для следующей очистки.
Плюсы: одновременный сбор, низкие паузы
Недостатки: генерировать много фрагментов, параллельная стадия снизит пропускную способность
G1
G1 — это сборщик, целью которого является оптимизация времени паузы GC.Он пытается достичь цели времени паузы GC с высокой вероятностью, достигая при этом высокой пропускной способности. В G1 вся структура памяти кучи изменена.В G1 вся куча разделена на несколько независимых областей одинакового размера.Хотя новое поколение и старое поколение логически сохранены, они физически изолированы. G1 выглядит следующим образом:
Умный шкаф на приведенном выше рисунке разделен на группу регионов одинакового размера.Каждый регион представляет собой непрерывный диапазон виртуальной памяти.G1 может знать, какой регион в основном пуст, чтобы его можно было предпочтительно перерабатывать в каждое разрешенное время сбора. Район с наибольшей ценностью (по размеру пространства, полученного при переработке, и времени, необходимому для переработки), поэтому G1 называется Мусор-Первый. G1 — сборщик мусора по умолчанию для jdk1.8.
Рабочий процесс G1 очень похож на CMS, разница находится на последнем этапе. Есть также четыре шага:
- Начальный тег: требует STW, помечает объекты, связанные с корнями GC, и изменяет значение TAMS (NEXT TOP AT MARK START), позволяя на следующем этапе создать объект в правильно доступной области.
- Параллельная маркировка: как и CMS, она в основном ищет корни GC, чтобы найти уцелевшие объекты для маркировки.
- Окончательная маркировка: требуется STW.Как и CMS, этот этап предназначен для исправления объектов, которые изменились в результате выполнения пользовательской программы во время параллельной маркировки.
- Screening и Recycling: сортируйте значение рециркуляции и стоимость каждого региона и формулируют план переработки в соответствии с ожидаемым временем паузы GC пользователем.
Первый фокус G1 состоит в том, чтобы обеспечить решение для пользователей, которым нужна большая задержка кучи и GC, что означает, что размер кучи около 6 г или выше, а стабильная и предсказуемая пауза составляет менее 0,5 секунды., Если приложение имеет следующие функции, вы можете рассмотреть возможность переключения на коллектор G1:
- Более 50% кучи Java занимают данные реального времени
- Ставки размещения или продвижения объектов сильно различаются
- Время паузы GC текущего приложения, чем 0,5 секунды, хотите сократить время паузы
другие коллекционеры
- Сборщик ZGC: сборщик мусора, предоставляемый Java11.
- Shenandoah: сборщик, включенный в Open JDK.
Как выбрать коллектор
- Серийные сборщики: Serial и Serial Old однопоточная коллекция для встраиваемых устройств с небольшим объемом памяти.
- Параллельный сборщик [приоритет пропускной способности]: Parallel Scanvage + Parallel OLD, подходит для научных расчетов, фоновой обработки и других сцен.
- Параллельный сборщик [приоритет времени паузы GC]: CMS и G1, подходящие для сценариев, требующих времени, таких как веб-приложения.
Настройка JVM
параметры JVM
Так называемая настройка JVM заключается в установке разумных параметров JVM, подходящих для текущей работы системы. Параметры JVM делятся на три категории: стандартные параметры, параметры -X и параметры -XX.
Стандартные параметры
Параметры, начинающиеся с "-", называются стандартными параметрами, которые поддерживаются любой версией JDK, являются относительно стабильными и не будут обновляться или изменяться в версии JDK. Например -версия, -помощь, -сервер.
-X параметр
Параметры, начинающиеся с -X, это команды, поддерживаемые конкретной версией HotSpot.После изменения версии jdk параметры могут измениться, и этот параметр используется реже.
-ХХ параметр
-Xx - нестабильный параметр, а также является основным параметром, разделенным на логический тип и не булевой тип.
Логический тип
-Xx Boolean Type Parameter имеет формат:
-XX:[+-]<name>:+或-表示启用或者禁用name属性
Например:
-XX:+UseConcMarkSweepGC:表示启用CMS垃圾收集器
-XX:+UseG1GC:表示启用G1垃圾收集器
-XX:+PrintFlagsFinal:表示打印出所有的JVM参数信息
Используйте IDEA, выберите Run->Edit Configurations, а затем нажмите плюсик слева, выберите Application, следующий интерфейс, добавление параметров JVM
Затем запустите основной метод, он распечатает все параметры
небулев
Формат использования нелогического параметра -XX:
-XX<name>=<value>:name表示属性,value表示属性对应的值
Например:
-XX:MaxMetaspaceSize=5M 设置最大永久代空间大小为5M
Другие параметры
Есть еще несколько очень полезных параметров, таких как -Xms, -Xmx, -Xss, по сути, это тоже параметры -XX, но сокращенные.
-Xms1000等价于-XX:InitialHeapSize=1000
-Xmx1000等价于-XX:MaxHeapSize=1000
-Xss1000等价于-XX:ThreadStackSize=1000
Общие параметры JVM
настраивать | инструкция |
---|---|
-XX:ClCompilerCount=3 | Максимальное количество параллельных компиляций.Когда оно больше 1, скорость компиляции может быть увеличена, но это повлияет на стабильность системы. |
-XX:InitialHeapSize=100m | Начальный размер кучи, может быть сокращен как -Xms100 |
-XX:MaxHeapSize | Максимальный размер кучи, может быть сокращен как -Xmx100 |
-XX:NewSize=20m | Установить размер молодого поколения |
-XX:MaxNewSize | Установите максимум молодому поколению |
-XX:OldSize=50m | Установить старческий размер |
-XX:MetaspaceSize=50m | Установите размер области метода, доступный только в jdk1.8, замените область метода метапространством |
-XX:+UseParallelGC | Установите Parallel Scanvage в качестве коллектора нового поколения, система по умолчанию выберет Parallel Old в качестве коллектора старого поколения. |
-XX:NewRatio | Отношение нового поколения к старому, например -XX:NewRatio=4 означает новое поколение: старое поколение=1:4 |
-XX:SurvivorRatio | Указывает соотношение между двумя областями S и областью Eden, например -XX:SurvivorRatio=8 означает (S0+S1):Eden=2:8 |
средство контроля команд
В каталоге bin jdk есть много инструментов для мониторинга jvm.
jps
jps полное имя инструмента состояния процесса JVM, процесса просмотра java. Просмотр текущих служб Java процесса, работающих под идентификатором и именем среды.
- -q: только идентификатор процесса вывода
- -m: выводить параметры, переданные методу main() при запуске виртуальной машины.
- -l: вывести полное имя основного класса, если выполняется jar-пакет, путь выходного jar-пакета
- -v: выходные параметры для запуска виртуальной машины
jstat
Полное название jstat — JVM Statistics Monitoring, инструмент для мониторинга различной статистики состояния виртуальных машин, в основном отображающий следующую информацию: загрузка классов, память, сборка мусора, JIT-компиляция и т. д. процессов виртуальной машины.
- Просмотр информации о загрузке класса
jstat -class PID 1000 10 //查看某个Java进程的类装载信息,每1000毫秒输出一次,共输出10次
- Просмотр информации о сборке мусора
jstat -gc PID 1000 10
На приведенном выше рисунке показана ситуация с каждой областью и сборкой мусора.Конкретные значения следующие (C означает емкость, U означает используемый размер).
- SOC и S1C представляют собой размер S0 и S1 области Survivor.
- S0U и S1U указывают используемое пространство
- EC указывает размер области Eden, EU указывает используемую емкость области Eden.
- OC представляет собой размер старости, а OU представляет собой используемую емкость старости.
- MC указывает размер области метода, MU указывает используемую емкость области метода.
- Класс CCSC представляет пространство сжатия, CCSU выражает сжатие размера используемого пространства.
- YGC заявила, что количество GC нового поколения, YGT, указывает на общее время, затраченное на GC нового поколения.
- FGC означает количество полных GC, FGCT означает общее время FULL GC
- GCT указывает общее время, затраченное на GC
Общие опции для параметров jstat
| Название | | | Параметры | Описание | | -класс | Посмотреть номер и размер нагрузки класса / разгрузки, а время, необходимое | | -GC | подсчитывать общий размер и используемый размер каждого раздела в куче, а также время GC и трудоемкости разных разделов | | -gccapacity | похожи на -gc, но в основном считает максимальное и минимальное пространство, используемое каждой областью кучи Java | | -GCUTIL | похожи на -GC, но в основном считает использованное пространство в процентах от общего пространства | | -gcouse | такой же, как -gcutil, но дополнительно вывод причины последнего возникновения GC | | -GCNew | Считать ситуацию GC нового поколения | | -gcold | Считать положение GC старости |
jstack
Трассировка стека для Java, инструмент снимка для генерации информации о состоянии потока для текущего времени, это очень полезно для анализа текущего состояния потока, например, какой поток заблокирован, или если есть тупик и другая информация. как:
jstack PID
Вы можете видеть статус текущего потока и имя потока, поэтому рекомендуется использовать собственное имя при создании потока самостоятельно, Если есть исключение, это легко узнать.
jinfo
Информация о конфигурации для Java, представление в реальном времени и изменить инструмент параметров JVM. Обратите внимание, что если он модифицируется, тип параметра управляемый тип для изменения.
jinfo -flag name PID 查看某个java进程的name属性的值
jinfo -flags PID 查看已经复制的JVM参数
jmap
Карта памяти для Java, команда для создания моментальных снимков дампа кучи или файлов дампа.
jmap -heap PID //打印出堆内存相关信息
jmap -dump:format=b,file=/usr/heap.hprof PID //生成dump文件
Вышеупомянутые общие параметры могут быть установлены, и как только произойдет OOM, файл дампа будет создан автоматически.
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof
jhat
JVM Heap Analysis Tool, инструмент для анализа файлов DUMP.
jhat heap.hprof
Затем получить доступ к адресуhttp://локальный:7000/,Вы можете видеть, что информация, отображаемая этим инструментом, относительно проста.
Инструмент визуального мониторинга
JConsole Tool.
Консоль мониторинга и управления Java, инструмент визуального мониторинга, поставляемый с JDK, на самом деле представляет собой визуализацию вышеупомянутых инструментов jstat, jstack и других командных инструментов, в основном для просмотра текущего обзора приложений Java, отслеживания информации о куче, использования постоянной области, загрузки классов. ситуация и др. jconsole может напрямую ввести команду jconsole в командной строке или найти и открыть ее в каталоге установки jdk.
Инструменты VisualVM
All-in-one Java TroubleshootingTool — это мощный инструмент для мониторинга операций и устранения неполадок, выпущенный JDK.
- Контролируйте ЦП приложения, GC, кучу. Область метода и информация о потоке (функции jstack и jstat)
- файл дампа и анализ (функция jmap и jhat)
- Анализ производительности программы на уровне методов, вы можете найти метод, который вызывается чаще всего и имеет наибольшее время выполнения.
- Снимок автономной программы: сбор конфигурации времени выполнения программы, дамп потока. Создайте снимок информации, такой как дамп памяти, и отправьте снимок разработчикам для получения отзывов об ошибках.
- Плагин обработки, неограниченные возможности расширения
ГК Анализ мелодии журнала
Что произойдет, когда ГК
Вообще есть несколько случаев:
- Недостаточно площади Eden или недостаточно площади S
- Не хватает старости
- Недостаточно области метода
- System.gc()
Как получить журналы GC
Чтобы распечатать журнал GC, вы можете использовать команду:
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:/Users/lizhengqiang/Documents/gc.log
Найдите файл gc.log, сборка мусора в начале отсутствует, поэтому файл пустой, дождитесь, пока произойдет сбор мусора, и откройте его
Параллельная очистка + параллельный анализ старых журналов
Первые три строки легче понять:
- Первая строка выводит используемую в данный момент виртуальную машину HotSpot и соответствующий номер версии.
- Вторая строка выводит информацию о памяти операционной системы.
- Третья строка — установленный параметр JVM.
Начало строки 4 — это наш журнал сборщика мусора. Давайте проанализируем строки 4 и 9 ниже.
//第4行
2020-08-23T15:35:30.747+0800: 5.486: [GC (Allocation Failure) [PSYoungGen: 32768K->3799K(37888K)] 32768K->3807K(123904K), 0.1129986 secs] [Times: user=0.02 sys=0.00, real=0.11 secs]
//第9行
2020-08-23T15:35:34.635+0800: 9.374: [Full GC (Metadata GC Threshold) [PSYoungGen: 5092K->0K(136192K)] [ParOldGen: 12221K->12686K(63488K)] 17314K->12686K(199680K), [Metaspace: 20660K->20660K(1067008K)], 0.0890985 secs] [Times: user=0.25 sys=0.00, real=0.09 secs]
- Первый раз 2020-08-23T15:35:30.747+0800 указывает время, когда происходит сборка мусора.
- Далее следует число европейских, чем 5,486, прошедших с момента запуска виртуальной машины Java в секундах.
- GC (ошибка распределения) указывает причину возникновения GC, здесь он представляет собой сбой выделения пространства.
- PSYoungGen, PS — сборщик Parallel Scavenge, YoungGen — молодое поколение.
- 32768K->3799K(37888K) означает: текущее использование области памяти до GC -> текущее использование области памяти после GC (общий объем памяти в текущей области). Отсюда видно, что после ГК большая часть места в молодом поколении осваивается.
- 32768K->3807K(123904K): Используемая емкость кучи до GC -> используемая емкость кучи после GC (общая емкость кучи Java)
- 0,1129986 секунд указывает время, затрачиваемое сборщиком мусора, секунды указывают, что единицей измерения являются секунды.
- [Times: user=0.02 sys=0.00, real=0.11 sec] Не все сборщики мусора будут печатать эту часть, usr=0.02 представляет время ЦП, потребляемое в пользовательском режиме, sys=0.00 представляет время ЦП и операции, потребляемые в режиме ядра Стена часов время, прошедшее от начала до конца.
- Строка 9 Полный сборщик мусора указывает, что произошел полный сборщик мусора.Полный сборщик мусора=минорный сборщик мусора+основной сборщик мусора+метапространственный сборщик мусора.Видно, что все новое поколение восстановлено, небольшая часть старого поколения восстановлена, а область метода вообще не восстанавливается. , что также отражает разницу между объектами, хранящимися в трех регионах.
Анализ журнала G1
Переключитесь на сборщик мусора G1, затем перезапустите службу и откройте gc.log после ожидания сборки мусора.
-Xms2m -Xmx2m -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:/Users/lizhengqiang/Documents/gc.log
Видно, что журнал G1 очень сложный, мы находим полный анализ журнала
2020-10-16T14:21:26.579-0800: 0.435: [GC pause (G1 Evacuation Pause) (young), 0.0013216 secs]
[Parallel Time: 1.0 ms, GC Workers: 4]
[GC Worker Start (ms): Min: 434.9, Avg: 434.9, Max: 434.9, Diff: 0.0]
[Ext Root Scanning (ms): Min: 0.2, Avg: 0.5, Max: 0.9, Diff: 0.7, Sum: 1.9]
[Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Object Copy (ms): Min: 0.0, Avg: 0.3, Max: 0.5, Diff: 0.5, Sum: 1.3]
[Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 0.5]
[Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 4]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
[GC Worker Total (ms): Min: 0.9, Avg: 0.9, Max: 0.9, Diff: 0.0, Sum: 3.8]
[GC Worker End (ms): Min: 435.8, Avg: 435.8, Max: 435.8, Diff: 0.0]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.0 ms]
[Other: 0.3 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.2 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.0 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 1024.0K(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->1024.0K Heap: 1024.0K(2048.0K)->464.1K(2048.0K)]
[Times: user=0.00 sys=0.00, real=0.01 secs]
- [Пауза GC (Пауза эвакуации G1) (молодой), 0,0013216 с] Это означает, что время, когда происходит GC, является молодым поколением, за которым следует общее время возникновения (Примечание: хотя G1 физически отменяет разделение области, оно все еще логически зарезервировано). , поэтому Young все равно будет отображаться в логе, а Full GC будет отображаться со смешанными)
- [Parallel Time: 1,0 мс, GC Workers: 4] Это предложение представляет параллельное время потока и количество параллельных потоков.
- [GC Worker Start (ms): Min: 434,9, Avg: 434,9, Max: 434,9, Diff: 0,0] Представляет собой минимальное, среднее и максимальное время запуска каждого параллельного потока, а также разницу во времени.