В некоторых языках есть механизм автоматического и безопасного освобождения оперативной памяти, ранее выделенной объектам в программе. Влияние разработчика на этот процесс опосредованное, прямого управления нет. Этот механизм принято называть Garbage collector (GC).
Некоторые языки возлагают ответственность за управление памятью на разработчика, например C, C++, Rust. В таком случае разработчик должен сам, в коде, вызвать метод удаления объекта, чтобы освобождать память. Если этого не делать, то можно получить [[утечку памяти]].
> Дай мне места для размещения того, что пока еще нужно. Дай мне смелости удалить то, что больше не пригодится. И дай мне мудрости, чтобы отличить одно от другого.
## Производительность GC
Вам быстро, дешево или качественно?
- **Throughput.** Объем вычислительных ресурсов CPU, затрачиваемых на работу GC.
- **Предсказуемость.** На какое время прерывается работа приложения.
- **Footprint.** Объем используемой памяти.
## Работа GC
Глобально у GC есть всего 2 задачи:
- Найти мусор. То есть понять, что объект больше не будет использоваться.
- И собрать мусор. Уничтожить такие объекты, чтобы на их месте можно было алоцировать новые.
> [!NOTE]
> В процессе своей работы GC не потребляет память в [[Heap]]
### Алгоритмы поиска мусора
#### Reference Counting
Этот алгоритм подсчитывает количество ссылок на каждый объект. Когда счетчик ссылок достигает нуля, объект считается недоступным.
Есть довольно много ситуаций, когда данный способ не работает. Например, циклический граф, где объекты ссылаются друг на друга, но они все являются мусором.
#### Tracing
Подсчет ссылок. Это наиболее распространенный алгоритм маркировки. Он начинается с изначально достижимых, "корневых" (GC Root), объектов и отслеживает все объекты, доступные от этих корней.
> [!QUESTION] Что может быть выбрано в качестве GC Root?
> Локальные переменные и статические переменные в Main классе и main методе, поток, который выполняет main, статические переменные, ссылки из JNI.
- Отдельный поток, который занимается поиском мусора и подает сигнал для запуска сборки.
- Как правило он один и работает параллельно с основной программой.
#### GC thread
- Отдельный поток, который занимается сборкой мусора.
- Таких потоков может быть много.
- Имеет несколько причин для старта.
- Может быть причиной StopTheWorld
### Причины старта GC
Главные:
- **Allocation Failure.** JVM попыталась выделить область памяти под новый объект, но памяти не хватило
- **GC Locker.** Кто-то подал сигнал на уборку.
Остальные:
- **Adaptive Size Ergonomics.**
- **Allocation Profiler.** Профайлер оказывает влияние на сборку мусора искажая показатели.
- **Heap Inspection.**
- **Heap Dump.**
- **No GC.** Если сборка мусора еще не запускалась или проходила давольно давно.
- **Last Ditch Collection.**
- **Perm Generation Ful.**
- **Meradata GC Threshold.**
### Minor Collection
^minor
Если количество используемой Eden Space памяти превышает некоторый заданный объем, то GC может выполнить быструю (minor) сборку мусора. По сравнению с полной сборкой мусора, данный процесс занимает немного времени и затрагивает только область молодого поколения, - устаревшие объекты без ссылок удаляются, а выжившие перемещаются в Survivor Space.
### Full Collection
В отличии от minor сборок охватывает весь Heap и занимает больше времени.
### Сборщики
- [Epsilon GC](Epsilon%20GC.md). Не собирает мусор :)
- [Serial GC](Serial%20GC.md). Морально устарел, но подойдет для консольных приложений.
- [Parallel GC](Parallel%20GC.md). Подходит для всех остальных случаев.
- [Concurrent Mark Sweep](Concurrent%20Mark%20Sweep.md). Минимизирует время простоя в приложениях с долгоживущими данными. Подходит для web-приложений.
- [Garbage First](Garbage%20First.md). Хорошо подходит для больших объемов памяти в сочетании с небольшими объектами.
- Ultra-low latency
- [ZGC](ZGC.md)
- [Shenandoah GC](Shenandoah%20GC.md)
По умолчанию обычно используется или [Serial](Serial%20GC.md) или [Parallel GC](Parallel%20GC.md).
![](Pasted%20image%2020231108140632.png)
## Как повлиять на сборку?
- Писать код с учетом особенностей работы GC. Неблагодарный труд.
- Использовать флаги JVM
Команда `System.gc()` носит рекомендательный характер. Разработчик рекомендует JVM запустить GC, но JVM может этого и не сделать.
## Мониторинг работы GC
Минимальные накладные расходы
Параметры VM
-`-XX:+PrintGCDetails -XX:+PrintGCTimeStamps`
-`-Xlog:gc` Показывает время [StopTheWorld](StopTheWorld.md).
- Стоит помнить про [Safe Point](Safe%20Point.md). Этот параметр показывает время без учета накладных расходов.
-`-Xlog:safepoint`. Показывает время с накладными расходами.
-`-Xloggc:<file>`
-`-XX:+PrintGcDateStamps`
-`-XX:+PrintHeapAtGC`
-`-XX:+PrintTenuringDistribution`
Анализ диагностического вывода:
- PrintGCStats
- GChisto
- VisualVM / VisualGC
## Дополнительные материалы
1. [Сборка мусора в Java](https://www.youtube.com/watch?v=St6iBm4sHl8).