1. Введение
Сборщик мусора (GC) обрабатывает управление памятью в Java. В результате программистам не нужно явно заботиться о выделении и освобождении памяти.
В Java JVM вначале резервирует определенный объем памяти. Иногда фактическая используемая память значительно меньше зарезервированного объема. В таких случаях мы предпочитаем возвращать лишнюю память ОС.
Весь этот процесс зависит от алгоритмов, используемых для сборки мусора . Следовательно, мы можем выбрать тип GC и JVM в соответствии с требуемым поведением.
В этом руководстве мы рассмотрим управление памятью с помощью GC и его взаимодействие с ОС.
2. Организация памяти JVM
Когда JVM инициализируется, внутри нее создаются различные типы областей памяти, такие как область кучи, область стека, область методов, регистры ПК и собственный стек методов.
GC имеет дело с хранилищем в куче. Следовательно, в этой статье мы сосредоточимся на взаимодействии с памятью, связанном с кучей.
Мы можем указать начальный и максимальный размеры кучи, используя флаги -Xms и -Xmx соответственно. Если -Xms меньше, чем -Xmx, это означает, что JVM не передала всю зарезервированную память в кучу в начале. Короче говоря, размер кучи начинается с -Xms и может увеличиваться до -Xmx . Это позволяет разработчику настроить размер требуемой кучи памяти.
Теперь при запуске приложения в куче выделяется память для разных объектов. Во время сборки мусора GC освобождает объекты, на которые нет ссылок, и освобождает память. Эта освобожденная память в настоящее время является частью самой кучи, поскольку это процедура, интенсивно использующая ЦП для взаимодействия с ОС после каждого освобождения.
Объекты располагаются разрозненно внутри кучи. Сборщику мусора необходимо сжать память и создать свободный блок для возврата в ОС . Он предполагает выполнение дополнительного процесса при возврате памяти . Кроме того, приложениям Java может потребоваться дополнительная память на более позднем этапе. Для этого нам нужно снова связаться с ОС, чтобы запросить больше памяти . Более того, мы не можем обеспечить наличие памяти в ОС в запрашиваемое время . Следовательно, более безопасным подходом является использование внутренней кучи вместо того, чтобы часто вызывать ОС для выборки памяти.
Однако, если нашим приложениям не требуется вся память кучи, мы просто блокируем доступные ресурсы, которые ОС могла бы использовать для других приложений. Учитывая это, JVM представила эффективные и автоматизированные методы освобождения памяти.
3. Сборщики мусора
Развиваясь в разных версиях релиза, Java представила разные типы GC . Взаимодействие с памятью между кучей и ОС зависит от реализаций JVM и GC. Некоторые реализации GC активно поддерживают сжатие кучи. Сокращение кучи — это процесс возврата избыточной памяти из кучи в ОС для оптимального использования ресурсов.
Например, Parallel GC не сразу освобождает неиспользуемую память обратно в ОС. С другой стороны, некоторые сборщики мусора анализируют потребление памяти и в соответствии с этим принимают решение об освобождении некоторой свободной памяти из кучи. Сборщики мусора G1, Serial, Shenandoah и Z поддерживают сжатие кучи.
Давайте теперь исследуем эти процессы.
3.1. Мусор в первую очередь (G1) GC
G1 является сборщиком мусора по умолчанию, начиная с Java 9. Он поддерживает процессы сжатия без длительных пауз. Используя внутренние алгоритмы адаптивной оптимизации, он анализирует объем оперативной памяти, необходимой для использования приложения, и при необходимости освобождает память .
Первоначальные реализации поддерживают сжатие кучи либо после полного GC, либо во время параллельных событий цикла. Однако в идеальной ситуации мы хотим оперативно возвращать неиспользуемую память ОС, особенно в периоды простоя нашего приложения. Мы хотим, чтобы сборщик мусора динамически адаптировался к использованию памяти нашими приложениями во время выполнения.
Java включает такие возможности в различные сборщики мусора. Для G1 эти изменения внесены в JEP 346 . Начиная с Java 12 и выше, сжатие кучи также возможно в фазе параллельных замечаний . G1 пытается проанализировать использование кучи, когда приложение простаивает, и запускает периодическую сборку мусора по мере необходимости . G1 может либо запустить параллельный цикл, либо полный сборщик мусора на основе параметра G1PeriodicGCInvokesConcurrent
. После выполнения цикла G1 необходимо изменить размер кучи и вернуть ОС освобожденную память.
3.2. Серийный GC
Serial GC также поддерживает сжатие кучи. По сравнению с G1 требуется четыре дополнительных полных цикла GC для дефиксации освобожденной памяти.
3.3. ЗГК
ZGC был представлен с Java 11. Он также был расширен за счет функции возврата неиспользуемой памяти в ОС в JEP 351 .
3.4. Шенандоа ГК
Shenandoah — это параллельный сборщик мусора. Он выполняет сборку мусора асинхронно . Устранение необходимости в полном сборщике мусора значительно помогает оптимизировать производительность приложения.
4. Использование флагов JVM
Ранее мы видели, что мы можем указать размеры кучи, используя параметры командной строки JVM. Точно так же мы можем использовать разные флаги для настройки поведения сборки мусора по умолчанию:
-XX:GCTimeRatio
: чтобы указать желаемое разделение времени между выполнением приложения и выполнением GC. Мы можем использовать его, чтобы заставить сборщик мусора работать дольше.-XX:MinHeapFreeRatio
: указать минимальную ожидаемую долю свободного места в куче после сборки мусора.-XX:MaxHeapFreeRatio
: указать максимально ожидаемую долю свободного места в куче после сборки мусора.
Если доступное свободное пространство в куче превышает соотношение, указанное с помощью параметра -XX:MaxHeapFreeRatio
, то сборщик мусора может вернуть неиспользуемую память ОС . Мы можем настроить значение вышеуказанных флагов, чтобы ограничить объем неиспользуемой памяти в куче. У нас есть аналогичные варианты для параллельных процессов сборки мусора:
-XX:InitiatingHeapOccupancyPercent
: чтобы указать процент заполнения кучи, необходимый для запуска параллельной сборки мусора.-XX:-ShrinkHeapInSteps
: немедленно уменьшить размер кучи дозначения -XX:MaxHeapFreeRatio
. Реализация по умолчанию требует для этого процесса нескольких циклов сборки мусора.
5. Вывод
В этой статье мы увидели, что Java предоставляет различные типы GC, отвечающие различным требованиям. Сборщик мусора может восстановить и вернуть свободную память хост-ОС. Мы можем выбрать тип GC в соответствии с нашими требованиями.
Мы также изучили использование параметров JVM для настройки поведения сборщика мусора для достижения желаемого уровня производительности. Кроме того, мы можем выбрать динамическое масштабирование использования памяти JVM. Мы должны учитывать компромиссы, связанные с каждым выбранным вариантом для нашего приложения и задействованными ресурсами.