digital-garden/knowledge/dev/java/gc/Garbage First.md

115 lines
13 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
aliases:
- G1
tags:
- зрелость/🌱
date: "[[2023-11-06]]"
zero-link:
- "[[../../../../garden/ru/meta/zero/00 Java разработка]]"
parents:
- "[[../../../../garden/ru/dev/java/gc/Garbage Collector]]"
linked:
---
Можно сказать, что этот сборщик пришел на замену [CMS](Concurrent%20Mark%20Sweep.md) в [Java 9](Java%209.md). Также, как и остальные сборщики использует подход [Generational Collection](Generational%20Collection.md), однако Heap разделяется не на большие части Young, Old, а на небольшие равные регионы.
Размер регионов по умолчанию 1 mb, но можно указать произвольное значение до 32 mb. Общее количество регионов в куче равно размеру кучи, деленному на размер региона. При настройке G1 рекомендуется ориентироваться на 2048 регионов, чтобы G1 работал эффективно.
И уже каждый сегмент может быть помечен как:
- eden - новые объекты, тут происходит [аллокация](Аллокация.md).
- survivor - объекты пережившие несколько сборок
- old - долгоживущие объекты
![](Pasted%20image%2020231107221815.png)
При этом у нас нет фиксированного размера под поколение. Каждый регион может отвечать за хранение молодых или старых объектов в разные моменты времени, что обеспечивает большую гибкость.
> [!INFO] Большой объект (humongous)
> Если объект занимает 2 и более сегмента, то он не перемещается за исключением Full GC. И в тот же сегмент не добавляются другие объекты, даже если у вас хватает места в регионе.
>
> ![](Pasted%20image%2020231107164540.png)
>
> В [[Java 11]] были внесены изменения в обработку больших объектов.
## Minor Collection
Minor сборка обычно происходит, когда eden заполняется. Над [minor](../../../../garden/ru/dev/java/gc/Garbage%20Collector.md#^minor) сборками мусора работают несколько потоков. Но очистка выполняется не на всем поколении, а только на регионах молодого поколения. За счет этого количество [StopTheWorld](StopTheWorld.md) становится больше, но сборка выполняется быстрее и не превышает желаемое время.
## Mixed Collection
Mixed сборка обрабатывает как молодое поколение, так и часть старого поколения. Эта запускается после определенного количества minor сборок.
В G1 существует процесс, называемый Marking Cycle, который работает параллельно с основным приложением и составляет список живых объектов. Он напоминает работу сборщика [CMS](Concurrent%20Mark%20Sweep.md).
- **Initial mark.** Пометка [GC Root](../../../../garden/ru/dev/java/gc/Garbage%20Collector.md#^gcroot) с использованием информации от [minor](../../../../garden/ru/dev/java/gc/Garbage%20Collector.md#^minor) сборок.
- В [Java 10](Java%2010.md) были внедрены улучшения. Параллельная пометка и улучшенное использование ресурсов процессора.
- **Concurrent marking.** Пометка всех живых объектов в heap. Работает в нескольких потоках.
- **Remark.** Дополнительный поиск не учтенных ранее живых объектов. Используется [StopTheWorld](StopTheWorld.md)
- **Cleanup.** Очистка вспомогательных структур учета ссылок на объект и поиск пустых регионов, которые уже можно использовать для размещения новых объектов. Первая часть этого шага выполняется с использованием [StopTheWorld](StopTheWorld.md).
Следует иметь в виду, что для получения списка живых объектов G1 использует алгоритм [Snapshot at the beginning (SATB)](Snapshot%20at%20the%20beginning%20(SATB).md), то есть в список живых попадают все объекты, которые были таковыми на момент начала работы алгоритма, плюс все объекты, созданные за время его выполнения. Это, в частности, означает, что G1 допускает наличие плавающего мусора.
После окончания цикла пометки G1 переключается на выполнение **смешанных сборок**. Это значит, что при каждой сборке к набору регионов младшего поколения, подлежащих очистке, добавляется некоторое количество регионов старшего поколения. Количество таких сборок и количество очищаемых регионов старшего поколения выбирается исходя из имеющейся у сборщика статистики о предыдущих сборках таким образом, чтобы не выходить за требуемое время сборки. Как только сборщик очистил достаточно памяти, он переключается обратно в режим minor сборок.
Очередной цикл пометки и, как следствие, очередные смешанные сборки будут запущены тогда, когда наполненность кучи превысит определенный порог.
## Full GC
Может оказаться так, что в процессе очистки памяти в куче не остается свободных регионов, в которые можно было бы копировать выжившие объекты. Это приводит к возникновению ситуации allocation (evacuation) failure. В таком случае сборщик выполняет полную сборку мусора по всей куче при остановленных основных потоках приложения.
С [[Java 9]] была реализована параллельная сборка мусора в этом режиме.
Опираясь на уже упомянутую статистику о предыдущих сборках, G1 может менять количество регионов, закрепленных за определенным поколением, для оптимизации будущих сборок.
## Дефрагментация
G1 копирует объекты из одной или нескольких областей кучи в одну область кучи, при этом одновременно сжимая и освобождая память. То есть используется подход [Copy Collector](Copy%20Collector.md). Этот процесс выполняется параллельно, чтобы уменьшить время пауз и увеличить пропускную способность.
Таким образом, при каждой сборке мусора G1 постоянно работает над уменьшением фрагментации, работая в пределах заданного пользователем времени паузы. Сборщик мусора CMS не выполняет дефрагментацию. Сборка мусора Parallel GC выполняет только сжатие всей кучи, что приводит к значительному времени паузы.
## Remembered Set
![](Pasted%20image%2020231108073803.png)
- Хранит информацию о местонахождении ссылок на объекты из региона
- Из старого в молодое поколение
- Между регионами в старом поколении
- Позволяет собирать регионы независимо
## Ситуации [StopTheWorld](StopTheWorld.md)
Если резюмировать, то у G1 мы получаем STW в следующих случаях:
1. Процессы переноса объектов между поколениями. Для минимизации таких пауз G1 использует несколько потоков, то есть [Parallel Collection](Parallel%20Collection.md)
2. Короткая фаза начальной пометки корней в рамках цикла пометки.
3. Более длинная пауза в конце фазы remark и в начале фазы cleanup цикла пометки.
## Работа с [барьерами](Барьеры%20в%20программировании.md)
Для работы G1 нужны барьеры 2 типов. Используются они для поддержания согласованности heap в момент сборки мусора.
- Pre-barrier
- Работает только, когда идет фоновая сборка мусора.
- Сохраняет старое значение поля
- Поддерживается корректность фоновой маркировки
- [SATB](../../../../garden/ru/dev/java/gc/Garbage%20Collector.md#^satb)
- Post-barrier
- Поддержка актуальности Remembered Set
- Не срабатывают, когда мы модифицируем указатель из молодого объекта в молодой
Результат сохраняется в буферы, локальные для потока. В процессе фоновой сборки происходит обработка.
## Выводы
**Минусы:**
- Очень плохо работает с объектами, которые занимают в памяти больше 1 mb.
- Не является сборщиком мусора в реальном времени. Имеются [StopTheWorld](StopTheWorld.md).
- Потребляет много ресурсов CPU, до 10% от всего потребления приложением.
**Плюсы:**
- Фоновый и параллельный.
- Ожидаемое, но не гарантированное, время пауз [StopTheWorld](StopTheWorld.md).
- Слабо подвержен фрагментации.
**Когда использовать:**
- Нужна хорошая производительность
- Изначально позиционировался для приложений, размер heap которых больше 4-5 Gb
- Продолжительность пауз 0,5-1 s
- Минимальная настройка
- Занятость кучи больше 50%
- Скорость создания объектов серьезно варьируется
**Когда не использовать:**
- Жесткие требования на паузы меньше 100 мс
- Требуется максимально возможный throughput даже в ущерб latency
**Как включить:**
- `-XX:+UseG1GC` - включение сборщика
- `-XX:MaxGCPauseMillis=` максимальная пауза для сборки мусора
- `-XX:GCPauseIntervalMills=` интервал между паузами
## Дополнительный материал
- [Getting Started with the G1 Garbage Collector](https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html)
- Документация Oracle.
- [Владимир Иванов — G1 Garbage Collector - YouTube](https://www.youtube.com/watch?v=iGRfyhE02lA)