Привет, Хабр!

JVM работает как хорошо отлаженный механизм, автоматически распределяя и освобождая память. Это и есть суть Garbage Collection. Это процесс, который автоматически находит и удаляет объекты, которые больше не используются вашим приложением. Благодаря этому, разработчики могут сосредоточиться на логике приложения, не беспокоясь о ручном управлении памятью.

Знание того, как работает GC и JVM, необходимо каждому Java-разработчику. Правильное управление ресурсами напрямую влияет на производительность и стабильность приложений.

Основные концепции GC

Кратко о структуре памяти в JVM

Куча (Heap)

Куча - это область памяти JVM, где хранятся все объекты Java и связанные с ними данные. Выделение памяти в куче происходит динамически во время выполнения программы.

Куча делится на несколько поколений для оптимизации сборки мусора:

Молодое поколение (Young Generation): Сюда помещаются вновь созданные объекты. Это поколение далее делится на области: Eden Space и две Survivor Spaces (S0 и S1).

Старое поколение (Old Generation): Содержит объекты, которые долго живут. Объекты перемещаются сюда из молодого поколения после того, как выживают несколько циклов сборки мусора.

Постоянное поколение (PermGen, до Java 8): Хранилище метаданных классов и строк до Java 8.

Размер кучи и соотношение между её различными областями можно настроить с помощью параметров JVM, что позволяет оптимизировать управление памятью в зависимости от потребностей приложения.

Стек (Stack)

Каждый поток в Java имеет собственный стек, который содержит информацию о вызовах методов и локальных переменных. Стек устроен по принципу LIFO (last-in, first-out) и используется для управления выполнением методов и их локальными переменными.

Каждый вызов метода создает новый фрейм стека, который содержит локальные переменные метода, параметры и информацию о выполнении. После завершения метода фрейм стека удаляется, освобождая память.

Размер стека ограничен и может быть настроен при запуске JVM. Если стек переполнен (обычно из-за глубокой или бесконечной рекурсии), JVM выбросит исключение java.lang.StackOverflowError.

Metaspace (замена PermGen в Java 8 и выше)

Metaspace используется для хранения метаданных классов и методов, в отличие от PermGen, который был удален в Java 8. В отличие от PermGen, Metaspace расширяется динамически, что помогает избежать ошибок OutOfMemoryError, связанных с метаданными классов.

Хотя Metaspace расширяется динамически, его максимальный размер все равно можно контролировать с помощью параметров JVM, что позволяет управлять потреблением памяти для метаданных.

Автоматическое управление памятью

Когда в Java создается новый объект, JVM автоматически выделяет для него необходимое количество памяти в куче (heap). Размер памяти, выделяемый под каждый объект, определяется его структурой: какие поля он имеет, какие типы данных используются и так далее.

Пока объект активно используется (на него есть ссылки в программе), он остается в памяти. Объекты могут быть доступны в различных областях памяти кучи, таких как Young Generation, Old Generation, и PermGen (в старых версиях JVM) или Metaspace (в новых версиях).

Garbage Collector (GC) работает в фоновом режиме и периодически проверяет, какие объекты в памяти больше не доступны для приложения. Это достигается путем отслеживания ссылок на объекты. Объект считается "мусором", если на него нет активных ссылок.

Как только объект идентифицирован как недоступный, GC освобождает память, занимаемую этим объектом. Это освобождает ресурсы и делает память доступной для новых объектов.

Помимо освобождения памяти, GC также может участвовать в оптимизации распределения памяти, например, путем сжатия оставшейся кучи для предотвращения фрагментации памяти.

Хотя управление памятью автоматизировано, понимание принципов его работы важно для оптимизации производительности и избегания проблем, таких как задержки из-за длительных операций сборки мусора. Неэффективное использование памяти и неправильная работа с объектами могут привести к чрезмерной нагрузке на сборщик мусора, что в свою очередь может вызвать проблемы с производодительностью.

Жизненный цикл объекта

Когда в Java создается новый объект (например, через оператор new), JVM выделяет для него память в куче (heap). Размер выделяемой памяти зависит от структуры объекта, включая его поля и связанные объекты.

После создания объект активно используется приложением. Это означает, что на объект существуют активные ссылки из других частей кода.

Обычные ссылки в Java являются сильными ссылками. Пока на объект есть хотя бы одна сильная ссылка, он остается в памяти.

Пример: MyClass myObject = new MyClass();

Java также предоставляет механизмы для создания слабых (WeakReference) и мягких (SoftReference) ссылок, которые позволяют GC удалять объекты, если это необходимо для освобождения памяти.

Если все сильные ссылки на объект обнулены или выходят из области видимости, объект становится недоступным для приложения.

Пример: myObject = null;

Когда выполнение блока кода завершается, все объекты, созданные в этом блоке и не связанные с внешними ссылками, также становятся недоступными.

GC периодически проверяет память на наличие объектов, которые больше не доступны (не имеют активных сильных ссылок. Этот процесс может быть инициирован автоматически или вручную (через вызов System.gc(), хотя его использование не рекомендуется).

После обнаружения недоступных объектов GC освобождает память, занимаемую этими объектами, делая её доступной для новых объектов.

Разные алгоритмы GC работают по-разному, и их эффективность может зависеть от характеристик приложения. Размеры областей памяти (например, Young и Old Generations) и другие параметры JVM также могут влиять на частоту и эффективность работы GC.

Генерационная гипотеза

Большинство объектов в приложении имеют короткий жизненный цикл. Они быстро создаются и также быстро становятся недоступными для использования. Относительно небольшое количество объектов используется в течение длительного времени (или в течение всего времени работы приложения).

Для оптимизации работы с различными типами объектов, JVM делит кучу (heap) на несколько "поколений" или областей:

Young Generation:

Здесь размещаются вновь созданные объекты. Young Generation далее делится на три части: Eden Space и две Survivor Spaces (S0 и S1). Поскольку большинство объектов в Young Generation быстро становятся "мусором", GC (Minor GC) часто и быстро очищает эту область.

Old Generation:

Объекты, которые выжили после нескольких циклов сборки мусора в Young Generation, перемещаются в Old Generation. Здесь объекты существуют гораздо дольше, и очистка этой области (Major GC) происходит реже, но она более трудоёмка.

Permanent Generation или Metaspace:

В этой области хранятся метаданные классов и другая информация на уровне приложения. В более новых версиях Java (начиная с Java 8) PermGen был заменен на Metaspace, который управляется немного иначе и хранится не в основной куче.

Работа GC с поколениями

Minor GC:

Young Generation в JVM делится на три части: одну область Eden и две Survivor области (S0 и S1). Новые объекты сначала размещаются в Eden. После заполнения Eden, Minor GC инициируется.

Minor GC начинается с поиска всех живых объектов в Eden и в одной из Survivor областей (которая активна в данный момент). Живые объекты копируются из Eden и активной Survivor области в другую Survivor область. Во время этого процесса, Eden и активная Survivor область очищаются.

Объекты, которые выживают после нескольких циклов Minor GC, перемещаются из области Survivor в Old Generation. Этот процесс называется "старением" объектов.

Minor GC выполняется часто и обычно занимает небольшое время, так как работает только с небольшими областями памяти. Поскольку он копирует объекты, а не удаляет их индивидуально, это снижает фрагментацию памяти.

Major GC или Full GC:

Old Generation предназначена для хранения долгоживущих объектов. Эта область больше по размеру по сравнению с Young Generation.

Major GC начинается с определения всех живых объектов в Old Generation. Все недоступные объекты удаляются. В отличие от Minor GC, этот процесс может включать уплотнение, чтобы уменьшить фрагментацию памяти.

Живые объекты могут быть перемещены для уменьшения фрагментации памяти, обеспечивая эффективное использование памяти для новых объектов.

Major GC выполняется реже, но является более трудоемким, так как обрабатывает больший объем памяти. Во время Major GC, приложение может испытывать более длительные паузы, так как это Stop-The-World процесс, где выполнение всех потоков приложения приостанавливается.

Типы GC в JVM

Serial Garbage Collector

Serial GC работает в однопоточном режиме, что означает, что во время сборки мусора все другие потоки приложения приостанавливаются (Stop-The-World пауза). Это самый простой и базовый сборщик мусора в JVM, без дополнительных сложностей многопоточной обработки или параллельной сборки мусора.

Когда Serial GC начинает процесс сборки мусора, он останавливает все другие потоки в приложении. Это означает, что выполнение приложения полностью приостанавливается на время сборки мусора.

Serial GC начинает с процесса маркировки, который определяет, какие объекты в куче все еще используются и должны быть сохранены. Он обходит все объекты, доступные из корневого набора (root set), который включает в себя глобальные переменные, активные потоки и т.д., маркируя каждый достижимый объект.

После маркировки GC удаляет все немаркированные объекты, освобождая занимаемую ими память. Это процесс называется очисткой.

В некоторых случаях, особенно если в куче много фрагментированной памяти, Serial GC может выполнить уплотнение. Это процесс, в ходе которого оставшиеся объекты перемещаются в непрерывный блок, что уменьшает фрагментацию памяти и упрощает последующее выделение памяти.

Не смотря на свою простоту и эффективность в средах с ограниченными ресурсами, SGC имеет ряд существенных недостатков.

Stop-The-World паузы могут быть проблематичными для приложений, требующих высокой отзывчивости или непрерывной работы.

Не подходит для многопроцессорных или многопоточных приложений, где требуется более высокая пропускная способность.

Parallel Garbage Collector (Throughput Collector)

Parallel GC использует несколько потоков для выполнения задач GC, что позволяет эффективно использовать многопроцессорные системы. Основная цель - максимизация пропускной способности приложения, то есть максимальное количество работы, которое приложение может выполнить за единицу времени.

Как и Serial GC, Parallel GC также инициирует Stop-The-World паузы. Во время этих пауз все потоки приложения приостанавливаются для выполнения задач GC.

В этой фазе GC идентифицирует все живые объекты в куче. Это достигается путём обхода всех объектов, начиная с корневого набора (который включает в себя глобальные переменные и активные потоки). Многопоточность используется для ускорения процесса обхода и маркировки.

После того как "живые" объекты определены, GC удаляет недоступные объекты, тем самым освобождая память. Эта фаза также может выполняться многопоточно для ускорения процесса.

В некоторых случаях может проводиться уплотнение памяти для уменьшения фрагментации. Это включает перемещение живых объектов так, чтобы они занимали непрерывный блок памяти. Уплотнение улучшает последующее выделение памяти, но может увеличить время паузы GC.

PGC позволяет нам добиться улучшенной производительности на многопроцессорных и многопоточных системах. Но не смотря на это возможны более длительные Stop-The-World паузы по сравнению с более специализированными сборщиками мусора.

Резюмируя - не всегда идеален для приложений, где критично время отклика.

Concurrent Mark-Sweep (CMS) Collector

CMS спроектирован для выполнения большей части своих задач одновременно с работой приложения, что минимизирует паузы, связанные с GC. Работа CMS делится на две основные фазы: фазу маркировки (Marking Phase) и фазу очистки (Sweeping Phase).

Фаза предварительной очистки (Initial Mark):

Это короткая Stop-The-World пауза, во время которой CMS маркирует корневые объекты, то есть объекты, доступные непосредственно из потоков приложения, глобальных переменных и т.д. Эта фаза быстра, но требует остановки всех потоков приложения.

Конкурентная фаза маркировки (Concurrent Marking):

В этой фазе, CMS продолжает процесс маркировки, обходя все объекты, достижимые из корневых объектов. Эта работа выполняется параллельно с выполнением приложения. Во время этой фазы приложение продолжает работать, что снижает влияние GC на время отклика приложения.

Фаза перемаркировки (Remark):

Это ещё одна короткая Stop-The-World пауза, во время которой CMS исправляет любые изменения, сделанные в куче после начала фазы конкурентной маркировки. Для оптимизации этого процесса часто используется алгоритм "снимка" (Snapshot-At-The-Beginning), который отслеживает изменения, произошедшие в куче с момента начала маркировки.

Конкурентная фаза очистки (Concurrent Sweeping):

После завершения маркировки, CMS удаляет немаркированные, а значит, недоступные объекты. Этот процесс также происходит параллельно с выполнением приложения. В результате, освобождается память, занимаемая недоступными объектами.

CMS обычно выбирают для серверных приложений и приложений в реальном времени, где важнее минимизировать время остановки, чем максимизировать пропускную способность или оптимизировать использование памяти. Однако, следует учитывать нагрузку на процессор и потенциальные проблемы с фрагментацией памяти, которая может быть из-за отсутствия уплотнения по умолчанию.

G1 Garbage Collector

G1 (Garbage-First) Garbage Collecto отличается от традиционных подходов, таких как CMS или Parallel GC, своей способностью более эффективно управлять системными ресурсами.

G1 GC разделяет кучу на множество небольших областей (регионов), что позволяет более гибко управлять памятью. Эти регионы могут быть различных типов, включая Eden, Survivor, и Old. G1 GC приоритизирует сборку мусора в тех регионах, где это наиболее эффективно, основываясь на объеме мусора и затратах на его очистку.

Как и в CMS, G1 начинается с короткой Stop-The-World паузы для маркировки корневых объектов. Это включает в себя объекты, которые непосредственно доступны из потоков приложения, статические объекты и т.д.

G1 продолжает процесс маркировки, обходя все объекты, доступные из корневых объектов, параллельно с выполнением приложения. В это время приложение продолжает работать, что снижает влияние GC на время отклика.

Далее идет фаза Final Mark, включает еще одну короткую Stop-The-World паузу, во время которой G1 завершает процесс маркировки. В эту фазу включается обработка изменений, которые произошли в куче с момента начала конкурентной маркировки.

В последней фазе (сборке мусора) G1 собирает мусор из отдельных регионов. Это может включать перемещение живых объектов из одного региона в другой. Эта фаза также является Stop-The-World паузой, но ее длительность более предсказуема и обычно короче, чем в традиционных GC.

G1 Garbage Collector подходит для приложений с большим объемом кучи, где важны как производительность, так и предсказуемое время остановки. Он идеально подходит к примеру для серверных приложений.

Z Garbage Collector (ZGC) и Shenandoah

Z Garbage Collector (ZGC) и Shenandoah предназначены для минимизации Stop-The-World (STW) пауз, что является маст хевом для приложений с требованиями к низкой задержке.

ZGC

ZGC разделяет кучу на набор мелких регионов. Это позволяет собирать мусор в каждом регионе независимо, что уменьшает время STW пауз. ZGC начинается с конкурентной фазы маркировки, которая происходит параллельно с работой приложения, минимизируя задержки.

Одной из ключевых особенностей ZGC является его способность к конкурентной релокации объектов. Это означает, что он может перемещать объекты во время работы приложения, что снижает необходимость в длительных STW паузах.

ZGC эффективно управляет фрагментацией памяти, регулярно уплотняя кучу во время работы приложения. ZGC использует цветные указатели и специальные барьеры чтения/записи для отслеживания доступных и перемещенных объектов, что позволяет оптимизировать процесс сборки мусора.

Shenandoah

Аналогично ZGC, Shenandoah выполняет большую часть работы по маркировке и компактизации конкурентно, то есть параллельно с выполнением приложения.

Shenandoah стремится минимизировать STW паузы, необходимые для некоторых задач сборки мусора. Shenandoah использует барьеры на пути выполнения для отслеживания доступа к объектам и их перемещения, что позволяет приложению продолжать работу во время сборки мусора.

Как и ZGC, Shenandoah активно управляет фрагментацией в куче, регулярно уплотняя пространство для эффективного выделения памяти.

Оба GC разработаны для обеспечения низких задержек в приложениях с большой кучей.

Подготовил небольшую обзорную табличку сравнения сборщиков:

Сборщик Мусора

Преимущества

Недостатки

Идеален для

Serial GC

Простота, эффективность для малых приложений

Низкая производительность на многопроцессорных системах

Малые приложения, ограниченные ресурсы

Parallel GC

Высокая пропускная способность

Длинные паузы GC

Серверные приложения, многопроцессорные системы

CMS

Низкие паузы GC

Возможная фрагментация памяти, сложность

Интерактивные приложения

G1 GC

Баланс между производительностью и задержкой, масштабируемость

Может требовать тонкой настройки

Большие серверные приложения

ZGC/Shenandoah

Минимальные паузы

Новизна, потенциальные ограничения в использовании

Приложения с требованиями к ультранизкой задержке

Тюнинг и мониторинг

JVM предоставляет множество параметров для настройки GC, включая размеры начальной и максимальной кучи (-Xms и -Xmx), размеры поколений (например, -XX:NewSize), а также выбор конкретного сборщика мусора (например, -XX:+UseG1GC для G1 GC).

Правильная настройка параметров GC зависит от характеристик приложения и доступных системных ресурсов. Например, увличение размера кучи может уменьшить частоту сборки мусора, но также может увеличить продолжительность каждой STW паузы.

Флаги JVM и переменные среды используются для тонкой настройки поведения GC, такие как управление поведением различных поколений объектов и настройка порогов для запуска сборки мусора.

JVM позволяет включить детальное логирование событий GC, что дает информацию о времени и продолжительности каждой сборки мусора, а также о количестве освобожденной памяти. Существуют различные инструменты для мониторинга работы GC в реальном времени, такие как VisualVM, JConsole или интегрированные средства мониторинга в различных IDE. Эти инструменты предоставляют визуализацию использования памяти и активности GC.

Анализ данных мониторинга и логов помогает выявить узкие места в производительности, связанные с управлением памятью, и дает понимание о том, как настройки GC влияют на поведение приложения.

Оптимизация и настройка GC

Существует множество параметров, которые позволяют контролировать поведение GC, управлять использованием памяти и оптимизировать производительность приложения. Эти параметры могут быть установлены при запуске JVM и охватывают различные моменты работы сборщиков мусора:

  1. -Xms<size> и -Xmx<size>:

    • Устанавливают начальный (-Xms) и максимальный (-Xmx) размер кучи.

    • Например, -Xms512m -Xmx4g устанавливает начальный размер кучи в 512 мегабайт и максимальный в 4 гигабайта.

  2. -XX:NewRatio=<ratio>:

    • Определяет соотношение между старым и молодым поколением в куче.

    • Например, -XX:NewRatio=2 означает, что старое поколение будет в два раза больше молодого.

  3. -XX:SurvivorRatio=<ratio>:

    • Определяет соотношение между каждой из Survivor областей и Eden областью в молодом поколении.

    • Например, -XX:SurvivorRatio=8 означает, что Eden будет в 8 раз больше каждой из Survivor областей.

  4. -XX:MaxTenuringThreshold=<value>:

    • Устанавливает максимальное количество циклов сборки мусора, после которых объект из молодого поколения перемещается в старое.

    • Более низкое значение означает более быстрое перемещение объектов в старое поколение.

  5. -XX:+Use<Collector>:

    • Указывает, какой сборщик мусора использовать. Например, -XX:+UseG1GC, -XX:+UseParallelGC, -XX:+UseConcMarkSweepGC.

Параметры для специфических сборщиков мусора

  1. Parallel GC:

    • -XX:ParallelGCThreads=<n>: Устанавливает количество потоков для сборки мусора в Parallel GC.

  2. CMS (Concurrent Mark-Sweep):

    • -XX:CMSInitiatingOccupancyFraction=<percent>: Указывает процент заполнения кучи, при котором начнется CMS cycle.

    • -XX:+UseCMSInitiatingOccupancyOnly: Указывает JVM использовать только заданный процент для начала CMS cycle.

  3. G1 GC:

    • -XX:MaxGCPauseMillis=<milliseconds>: Целевое значение для максимальной длительности паузы GC.

    • -XX:G1HeapRegionSize=<size>: Устанавливает размер региона в G1 GC.

  4. ZGC:

    • -XX:ConcGCThreads=<n>: Количество потоков, используемых для параллельной обработки в ZGC.

  5. Shenandoah:

    • -XX:ShenandoahGCHeuristics=<heuristic>: Определяет эвристику, которую Shenandoah будет использовать.

Для мониторинга и профилирования GCC используются различные инструменты, включая VisualVM, JConsole и логи GC:

VisualVM

VisualVM – это мощный инструмент для визуального мониторинга, диагностики и профилирования Java-приложений.

VisualVM позволяет отслеживать использование CPU, памяти и потоков в реальном времени. Инструмент предоставляет информацию о состоянии кучи (heap) и событиях сборки мусора, включая время пауз и частоту GC.

Позволяет идентифицировать "узкие места" в коде, анализировать использование памяти и производительность потоков.

JConsole

JConsole – это инструмент Java Monitoring and Management Console, который используется для мониторинга и управления приложениями Java.

Позволяет отслеживать использование памяти, загрузку CPU и активность потоков. Позволяет визуализировать использование различных областей памяти и возможность инициирования сборки мусора. Отображает информацию о Java-среде, включая версию, конфигурацию и библиотеки.

Подключается к JMX (Java Management Extensions) агенту для сбора данных о работе Java-приложения.

GC Logs

Логи GC – это файлы журналов, которые содержат подробную информацию о процессах сборки мусора в JVM.

Предоставляют информацию о времени начала и окончания каждой сборки мусора, а также о том, какие области памяти были очищены. Помогают идентифицировать потенциальные утечки памяти и неэффективное использование памяти.

Позволяют анализировать производительность GC в течение длительного времени.

Включение логирования GC производится с помощью флагов командной строки при запуске JVM, например, -Xlog:gc, -Xlog:gc* для Java 9+ или -XX:+PrintGCDetails для старых версий.

Утечки памяти, задержки и другие проблемы, связанные с производительностью и управлением памятью, являются распространенными трудностями при работе с Java-приложениями:

Утечки памяти

Утечки памяти происходят, когда объекты, которые больше не нужны приложению, по каким-то причинам не удаляются Garbage Collector'ом (GC), продолжая занимать память.

Причины:

Неправильное управление ресурсами: Например, не закрытые соединения или потоки.

Статические коллекции: Статические переменные, сохраняющие ссылки на объекты.

Листенеры и коллбеки: Объекты, зарегистрированные в качестве слушателей или коллбеков, и не отмененные должным образом.

Решения:

  • Профилирование памяти: Использование инструментов, таких как VisualVM или JProfiler, для обнаружения объектов, которые занимают большую часть памяти и не освобождаются.

  • Анализ кода: Поиск потенциальных утечек памяти, особенно в статических полях и коллекциях.

  • Использование Weak References: Использование слабых ссылок для объектов, которые могут быть освобождены GC.

  • Правильное управление ресурсами: Закрытие всех ресурсов (соединения, потоки) в блоках finally или с помощью конструкций try-with-resources.

Задержки

Задержки, часто связанные с процессами GC, влияют на время отклика приложения.

Причины:

  1. Чрезмерная активность GC: Вызвана недостаточным объемом памяти или частым созданием объектов.

  2. Неподходящий выбор GC: Использование GC, не подходящего для специфики приложения.

Решения:

  • Оптимизация размера кучи: Увеличение -Xmx и -Xms для предоставления большего объема памяти приложению.

  • Выбор подходящего GC: Эксперименты с разными сборщиками мусора для определения оптимального.

  • Тюнинг GC: Настройка параметров GC, например, -XX:NewSize, -XX:MaxNewSize, -XX:SurvivorRatio.

Немного примеров настройки GC

Настройка сборщика мусора в Java Virtual Machine (JVM) обычно не включает написание кода, поскольку она осуществляется через параметры командной строки при запуске JVM. Однако, рассмотрим примеры, где проведем настройку gc через код:

Пример 1

Настроить GC для веб-серверного приложения, где приоритетом является минимизация времени остановки для низкой задержки.

Код:

java -XX:+UseG1GC -Xms4G -Xmx4G -XX:MaxGCPauseMillis=200 -jar my-web-app.jar
  • -XX:+UseG1GC: Использование G1 GC, который подходит для приложений с большим объемом памяти и требующих низких пауз GC.

  • -Xms4G и -Xmx4G: Установка начального и максимального размера кучи в 4 ГБ.

  • -XX:MaxGCPauseMillis=200: Целевое значение для максимальной длительности паузы GC в 200 мс.

Пример 2

Настроить GC для приложения обработки больших данных, где важна общая пропускная способность и эффективность использования памяти.

Код:

java -XX:+UseParallelGC -Xms8G -Xmx8G -XX:ParallelGCThreads=8 -jar my-data-processing-app.jar
  • -XX:+UseParallelGC: Использование Parallel GC, который эффективен для многопоточных систем.

  • -Xms8G и -Xmx8G: Установка начального и максимального размера кучи в 8 ГБ.

  • -XX:ParallelGCThreads=8: Установка количества потоков для Parallel GC, оптимизировано для многопроцессорных систем.

Пример 3

Настроить GC для настольного приложения с пользовательским интерфейсом, требующего коротких пауз GC для обеспечения плавности работы.

Код:

java -XX:+UseConcMarkSweepGC -Xms512M -Xmx512M -jar my-desktop-app.jar
  • -XX:+UseConcMarkSweepGC: Использование CMS GC, который минимизирует время остановки приложения.

  • -Xms512M и -Xmx512M: Установка начального и максимального размера кучи в 512 МБ, достаточно для многих настольных приложений.

Пример 4

Настроить GC для сервера приложений, обрабатывающего высокие нагрузки и требующего большого объема памяти и высокой пропускной способности.

Код:

java -XX:+UseG1GC -Xms16G -Xmx16G -XX:ConcGCThreads=10 -jar my-high-load-server-app.jar
  • -XX:+UseG1GC: Использование G1 GC, который подходит для серверных приложений с большим объемом памяти.

  • -Xms16Gи-Xmx16G: Установка начального и максимального размера кучи в 16 ГБ.

  • -XX:ConcGCThreads=10: Настройка количества потоков для параллельной сборки мусора.

Пример 5

Настроить GC для приложения с критически важными требованиями к низкой задержке.

Код:

java -XX:+UseZGC -Xms4G -Xmx4G -jar my-low-latency-app.jar
  • -XX:+UseZGC: Использование Z Garbage Collector, который предназначен для систем с ультранизкими задержками.

  • -Xms4G и -Xmx4G: Установка начального и максимального размера кучи в 4 ГБ для управления большими объемами данных с минимальными паузами.

В заключение, правильное применение GC в JVM может значительно улучшить производительность приложений, снизить задержки, предотвратить утечки памяти и улучшить общее управление ресурсами. В конечном итоге, это приводит к созданию более надежных, эффективных и высокопроизводительных приложений, способных удовлетворять самые разнообразные требования и условия эксплуатации.

Статья подготовлена в преддверии запуска нового потока курса Java Developer. Professional. Вы, наверняка, знаете, что работа над Virtual Threads (JEP444) наконец-то завершена. Приглашаю вас на бесплатный вебинар курса, где посмотрим, что и итоге получилось и как этим пользоваться. Зарегистрироваться.

А 12 декабря посмотрим, как можно сделать самодельный appender для Logback. Appender будет отправлять логи в TCP сервер логирования. Зарегистрироваться.

Комментарии (7)


  1. lobotomic
    27.11.2023 16:13
    +5

    Низкий поклон за столь подробную и глубокую статью!

    Знание того, как работает GC и JVM, необходимо каждому Java-разработчику.

    В этом я очень сомневаюсь. Общее представление об этом, несомненно, нужно каждому. Но столь детальные сведения, как в этой статье, нужны примерно кождому сотому разработчику, а именно тем, кто занимается высонагруженными и многопоточными приложениями. Запомнить всё это на сколько нибудь продолжительное время невозможно, если ты этим не пользуешься постоянно. Вот когда человеку без этого будет не обойтись, он посмотрит в вашу статью и применит.


    1. Firsto
      27.11.2023 16:13

      Перед собеседованиями пригодится.)


    1. VADemon
      27.11.2023 16:13
      +1

      Низкий поклон за столь подробную и глубокую статью!

      Жмакать на "длинное": https://shipilev.net/#shenandoah


    1. yrub
      27.11.2023 16:13
      +1

      разработчики jvm делают все для упрощения тюнинга gc, чтобы простые люди туда не лезли. видимо авторы не застали времена java 7 и 8, когда CMS тюнили комбинацией из 10-15 мало кому понятных параметров, добиваясь минимальных STW.


  1. Beholder
    27.11.2023 16:13

    -XX:+UseConcMarkSweepGC: Использование CMS GC, который минимизирует время остановки приложения.

    Ага, только с 15 версии JDK его удалили, так что хоть проверяйте свои рецепты.


    1. a-tk
      27.11.2023 16:13
      +1

      Отус не читатели, отус писатели. Ну не умеет постраничный переводчик в технический фактчекинг


  1. Dasfex
    27.11.2023 16:13

    То ли я не увидел, то ли нет уточнения, что эти реализации сборщиков относятся только к hotspot jvm.

    Кажется, вы ещё много всего не упомянули :) Хотя бы mark-sweep, mark-compact, копирующий сборщик.