процесс размещения объектов
- 1) По анализу побега определить, можно ли его разместить в стеке?
- Если возможно, используйте скалярную замену, чтобы присвоить объект
VM Stack
середина. Если поток уничтожается или завершается вызов метода, он автоматически уничтожается без вмешательства сборщика мусора. - В противном случае перейдите к следующему шагу.
- Если возможно, используйте скалярную замену, чтобы присвоить объект
- 2) Определить, является ли это крупным объектом?
- Если да, выделить непосредственно в кучу
Old Generation
старость. Если объект становится мусором, он собирается сборщиком мусора старого поколения (например, Parallel Old, CMS, G1). - В противном случае перейдите к следующему шагу.
- Если да, выделить непосредственно в кучу
- 3) Определить, можно ли
TLAB
распределение?- Если да, то в
TLAB
выделенный в кучеEden
Площадь. - В противном случае в
TLAB
во внешней кучеEden
Распределение по районам.
- Если да, то в
выделение стека
По сути, это метод оптимизации, предоставляемый JVM.
- Основная идея: рассредоточить объекты, принадлежащие потоку, и разместить их в стеке.
VM Stack
начальство - преимущество:
- Объект может быть уничтожен сам по себе после завершения вызова функции, без вмешательства сборщика мусора, эффективно избегая негативного влияния сборки мусора
- Быстрое размещение в стеке, повышающее производительность системы
- ограничение:
- Размер стека небольшой, т.к.большой объектНевозможно выделить в стеке
- техническая база:
逃逸分析
,标量替换
Что такое анализ побега?
Определение escape-анализа Java:
Escape Analysis — это просто метод, с помощью которого виртуальная машина Java Hotspot может анализировать область использования вновь созданных объектов и решать, следует ли выделять память в куче Java.
Параметры JVM для анализа выхода следующие:
- Включите анализ побега:
-XX:+DoEscapeAnalysis
- Отключите анализ побега:
-XX:-DoEscapeAnalysis
- Отображение результатов анализа:
-XX:+PrintEscapeAnalysis
Технология анализа экранирования поддерживается в Java SE 6u23+ и включена по умолчанию, поэтому этот параметр не требуется.
Оптимизация анализа побега
Для третьего пункта выше, когда объект не исчезает, можно получить следующие оптимизации виртуальной машины.
1) Снятие замка
Мы знаем, что блокировка синхронизации потока снижает производительность.Когда компилятор определяет, что текущий объект используется только текущим потоком, он снимает блокировку синхронизации объекта.
Например, StringBuffer и Vector являются потокобезопасными с синхронизированным оформлением, но в большинстве случаев они используются только в текущем потоке, поэтому компилятор оптимизирует эти операции блокировки.
Параметры JVM для снятия блокировки следующие:
- Снятие открытого замка:
-XX:+EliminateLocks
- Удаление закрытого замка:
-XX:-EliminateLocks
Устранение блокировки включено по умолчанию в JDK8, и устранение блокировки должно быть установлено ванализ побегана основе.
2) Скалярная замена
Первое, что нужно понять, это скаляры и агрегаты, ссылки на примитивы и объекты можно понимать как скаляры, они не подлежат дальнейшей декомпозиции. Величины, которые могут быть дополнительно декомпозированы, являются агрегатными величинами, такими как объекты.
Объект представляет собой совокупную величину, которая может быть далее разложена на скаляры, а его переменные-члены разложены на дискретные переменные, что называется标量替换
.
Таким образом, если объект не экранируется, его вообще не нужно создавать, а в стеке или регистрах создаются только скаляры-члены, которые он использует, что экономит место в памяти и повышает производительность приложения.
Аргументы JVM для скалярной замены следующие:
- Включите скалярную замену:
-XX:+EliminateAllocations
- Отключите скалярную замену:
-XX:-EliminateAllocations
- Показать детали скалярной замены:
-XX:+PrintEliminateAllocations
Скалярная замена также включена по умолчанию в JDK8 и основана на анализе побега.
3) Размещение в стеке
Когда объект не экранируется, объект может быть разложен на скаляры-члены и размещен в памяти стека путем скалярной замены, что согласуется с жизненным циклом метода.Он уничтожается, когда кадр стека извлекается из стека, что снижает нагрузку на ГХ и повышает производительность приложений.
образец кода
import java.time.Instant;
/**
* 栈上分配,依赖于逃逸分析和标量替换
*
* @author Sven Augustus
*/
public class TestTLAB {
// private static User u;
/**
* 一个User对象的大小:markdown 8 + class pointer 4 + int 4 + string (oops) 4 + padding 4 = 24B <br> 如果分配 100_000_000 个,则需要
* 2400_000_000 字节, 约 2.24 GB。
*/
static class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
private static void alloc() {
User u = new User(1, "SvenAugustus");
// u = new User(1, "SvenAugustus");
}
public static void main(String[] args) throws InterruptedException {
long start = Instant.now().toEpochMilli();
for (int i = 0; i < 100_000_000; i++) {
alloc();
}
System.out.println(Instant.now().toEpochMilli() - start);
}
}
Приведенный выше код вызывает alloc() 100 миллионов раз. Если он выделен в кучу, ему потребуется около 2,2 ГБ пространства в куче. Если пространство в куче меньше этого значения, сборщик мусора неизбежно сработает.
Запустите со следующими параметрами виртуальной машины и обнаружите, что GC не будет запускаться:
-server -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations
Запустите со следующими параметрами (любая строка), вы найдете много GC:
//不使用逃逸分析
-server -Xmx15m -Xms15m -XX:+PrintGCDetails -XX:-UseTLAB -XX:-DoEscapeAnalysis -XX:+EliminateAllocations
//不使用标量替换
-server -Xmx15m -Xms15m -XX:+PrintGCDetails -XX:-UseTLAB -XX:+DoEscapeAnalysis -XX:-EliminateAllocations
Назначение TLAB
TLAB, полное имя локального буфера распределения потоков, это: буфер локального распределения потоков. Это область выделения памяти для конкретного потока.
TLAB занимает пространство области Эдема.
Когда TLAB включен (включен по умолчанию), JVM выделяет область TLAB для каждого потока.
Зачем нужны TLAB?
Это сделано для ускорения выделения объектов.
Поскольку объекты обычно размещаются в куче, а куча совместно используется потоками, на место в куче могут претендовать несколько потоков, и каждое выделение объекта должно синхронизироваться потоками, что снизит эффективность выделения.
Учитывая, что выделение объектов — едва ли не наиболее часто используемая операция в Java, JVM использует область, специфичную для потоков, такую как TLAB, чтобы избежать многопоточных конфликтов и повысить эффективность выделения объектов.
- Ограничения: пространство TLAB, как правило, не слишком велико (занимает область Эдема), поэтомубольшой объектне могу продолжить
TLAB
Выделено, может быть выделено только непосредственно в кучуHeap
начальство.
большой объект
Параметры JVM для больших объектов следующие:
- Насколько велик большой объект:
-XX:PreTenureSizeThreshold=n
(применимо только кDefNew
/ParNew
Сборщик мусора молодого поколения)не говорите .open JDK.java.net/browse/JDK-… -
G1
Суждение коллекционера о крупных объектах основано наRegion
размер(-XX:G1HeapRegionSize
), чтобы судить, больше ли объект, чемRegion
Более 50% оценивается как крупный объектHumongous Object
.
by Sven Augustus my.oschina.net/langxSpirit