Java GC: краткий обзор перед интервью
2 марта 2023 г.
Авторские права на изображение: LIK Studio
Вопрос о сборщиках мусора стал вирусным. Это можно услышать почти в каждом интервью. Поэтому я собрал всю необходимую информацию в одном месте и воспользовался своим излюбленным принципом — кратко и просто.
Итак, давайте начнем с цели компьютерной графики и почему нам нужны несколько типов сборщиков мусора.
Идея: дать программисту языковой инструмент для управления памятью вместо него самого.
Решение. Создайте систему сбора мусора.
В таких языках, как C, нам нужно хранить информацию о наших сущностях в нашей памяти и писать много стандартного кода, чтобы освободить память.
Никто не идеален. Так что утечки памяти — частые гости в таких программах. Java решает эту проблему с помощью сборщика мусора, но вы должны знать, какой сборщик мусора поможет вам лучше.
Ваша программа может работать на слабом оборудовании, или ваша программа будет работать с большим количеством объектов, или ваша программа должна быть быстрой.
Вы должны настроить свой GC для достижения желаемой производительности во всех этих ситуациях. Итак, приступим.
Как JVM работает с памятью
JVM делит свою память на две области: куча, в которой хранятся данные приложения, и некуча, в которой хранится программный код и другие данные.
Обратим внимание на область кучи. Потому что именно в этом месте наша программа создает новые объекты.
(Примечание: мы также можем создавать некоторые записи в областях вне кучи. Например, если наша программа создает новые классы на лету)
Все сборщики мусора основаны на одном важном наблюдении — многие программы используют недолговечные объекты. Эти объекты созданы, выполнили свою функцию и больше не нужны. Они преобладают. Некоторые объекты живут намного дольше, возможно, даже все время жизни программы.
Вот тут-то и возникает идея разделения объектов на молодое и старое поколения. Нужно очень часто проверять молодое поколение.
Так что в соответствии с этим делением процессы сборки мусора делятся на минорный GC, который затрагивает только младшее поколение, и полный GC, который может затрагивать оба поколения.
КГ это программа. И сначала для его работы требуется время и ресурсы вашего компьютера. И это также влияет на наше приложение.
Как?
Чтобы выполнить сборку мусора, JVM приостанавливает наше приложение. Итак, это называется паузой Stop-The-World (STW).
В это время все потоки приложений приостановлены. Приложение внутри об этом совершенно не подозревает. Для приложения время течет равномерно.
Почему это так плохо? Вот представьте, вы пишете какое-то приложение для обмена или приложение для автопилота самолета. Ваше приложение может «заснуть» на одну секунду, но контекст вашей проблемы может резко измениться.
Таким образом, эта пауза является важным параметром для каждого сборщика мусора.
Следующее фундаментальное свойство CG — это общее время, затраченное на сборку мусора, по отношению к общему времени выполнения программы. Что это значит и почему это так важно?
Вместо одной большой фазы «останови мир» мы можем найти алгоритм со множеством маленьких пауз.
Небольшие паузы предпочтительнее, но ничего не бывает бесплатно. В этом случае мы оплачиваем общее время выполнения программы. И мы тоже должны это учитывать.
Следующий параметр - это количество аппаратных ресурсов. Каждому CG требуется память для хранения информации об объектах и ЦП для выполнения очистки.
Последнее - Оперативность. Оперативность сборки мусора – это скорость и эффективность сборщика мусора (GC), который освобождает память, которая больше не используется программой.
Это искусство разработки алгоритма, который может максимально быстро освобождать память при минимальном потреблении ресурсов.
Давайте взглянем на доступные нам сборщики мусора.
Вам нужно знать первые пять для интервью. Два других гораздо сложнее.
Серийный сборщик мусора
Serial GC — это сборщик мусора в виртуальной машине Java, который использовался с первых дней Java. Это полезно для программ с крошечной кучей и работающих на менее мощных машинах.
Сборщик мусора делит кучу на регионы, включая регион Eden, куда помещаются вновь созданные объекты. По мере заполнения кучи объекты перемещаются между регионами Эдем и Выживший.
JVM постоянно отслеживает перемещение объектов между регионами Survivor и выбирает соответствующий порог количества таких перемещений, после чего объекты перемещаются в регион старшего поколения (Tenured).
Когда в регионе Tenured не хватает места, в дело вступает полная сборка мусора, работающая с объектами обоих поколений.
Основным преимуществом этого сборщика мусора являются его низкие накладные расходы и очень низкие ресурсы ЦП для выполнения сборки.
Основным недостатком являются длительные паузы при сборке мусора, особенно для больших объемов данных.
Параллельная компьютерная графика
Параллельная компьютерная графика похожа на последовательный конструктор, но включает параллельную обработку для некоторых задач и возможность автоматической настройки параметров производительности.
Parallel GC — это сборщик мусора в виртуальной машине Java, основанный на идеях Serial GC, но с добавлением параллелизма и интеллекта. Если компьютер имеет более одного ядра процессора, старая JVM автоматически выбирает Parallel GC (действительно для старых JSM).
Куча разделена на те же регионы, что и Serial GC — Eden, Survivor 0, Survivor 1 и Old Gen (Tenured). Однако в сборке мусора задействовано несколько потоков параллельно, и сборщик может подстроиться под требуемые параметры производительности.
У каждого потока-коллектора есть область памяти, которую нужно очистить. У Parallel GC также есть настройки, направленные на достижение требуемой эффективности сборки мусора, а сборщик использует статистику предыдущих сборок мусора, чтобы настроить параметры производительности для будущих сборок.
Parallel GC обеспечивает автоматическую настройку на желаемые параметры производительности и меньшее время паузы для сборки, а некоторая фрагментация памяти является незначительным недостатком. Он подходит для большинства приложений и не требует дополнительных затрат.
Однако для более сложных приложений необходимы расширенные реализации сборщиков мусора.
Плюсы: Во многих случаях быстрее, чем последовательный. Имеет хорошую пропускную способность.
Минусы: потребляет больше ресурсов, а паузы могут быть очень длинными, потому что мы можем настроить максимальную остановку мировой паузы.
Одновременная проверка меток
Concurrent Mark Sweep (CMS) направлен на сокращение максимальной задержки за счет выполнения некоторых задач по сбору мусора одновременно с потоками приложения и подходит для управления большими объемами данных в памяти.
Конструктор Concurrent Mark Sweep (CMS) — это альтернатива Parallel GC в виртуальной машине Java (JVM), разработанная для приложений, которым требуется доступ к нескольким ядрам ЦП и которые чувствительны к паузам Stop-The-World.
Конструктор CMS выполняет этапы сборки мусора Mark и Sweep параллельно с основной программой, что позволяет ей выполняться во время ее работы.
Он использует ту же организацию памяти, что и Serial и Parallel GC, но не ждет заполнения области Tenured перед запуском коллекции старого поколения.
Вместо этого он работает в фоновом режиме и пытается сохранить компактный регион Tenured.
Конструктор CMS начинается с начальной фазы маркировки, которая ненадолго останавливает основные потоки приложения и помечает все объекты, непосредственно доступные из корней.
После этого основные потоки приложения возобновляют работу, и CMS начинает поиск всех активных объектов, доступных по ссылкам из отмеченных корневых объектов.
После маркировки всех живых объектов сборщик в несколько параллельных потоков очищает память от мертвых объектов.
Одним из преимуществ CMS является ее направленность на минимизацию времени простоя, что имеет решающее значение для многих приложений. Однако для этого приходится жертвовать ресурсами ЦП и зачастую общей пропускной способностью.
Кроме того, CMS не сжимает объекты в старом поколении, что приводит к фрагментации. Долгие паузы из-за возможных сбоев в параллельном режиме могут стать неприятным сюрпризом, хотя они случаются нечасто, и CMS удается их избежать при наличии достаточного объема памяти.
Плюсы: Быстро. Имеет небольшие паузы STW.
Минусы: потребляет больше памяти, некоторые паузы могут быть длинными, не нравится, когда приложение создает много объектов.
Сначала мусор
Garbage-First (G1) предназначен для замены CMS, особенно для серверных приложений, использующих многопроцессорные серверы и управляющих большими наборами данных.
Сборщик мусора G1 организует память в несколько областей одинакового размера, за исключением огромных областей, которые создаются путем слияния обычных областей для размещения массивных объектов. Регионы не обязательно должны располагаться в ряд и могут менять принадлежность своего поколения.
Небольшие коллекции выполняются периодически для очистки младшего поколения и перемещения объектов в регионы Survivor или улучшения их до старшего поколения с переводом в Tenured.
Очистка выполняется только на части регионов, чтобы избежать превышения желаемого времени, и выбирает для очистки те регионы с наибольшим количеством мусора ( CG пытается предсказать такие области).
Полные коллекции используют цикл маркировки, который работает параллельно с основным приложением для перечисления живых объектов. После цикла маркировки G1 переключается на запуск смешанных коллекций, которые добавляют регионы старшего поколения к набору регионов младшего поколения, подлежащих очистке.
Количество таких сборок выбирается на основе статистики о предыдущих сборках, чтобы уложиться в требуемое время сборки.
Сборщик мусора G1 считается более точным, чем сборщик CMS, в прогнозировании размеров пауз и лучше распределяет сбор мусора во времени, чтобы предотвратить длительные простои приложений, особенно при больших размерах кучи.
Он также не фрагментирует память, как сборщик CMS.
Однако сборщику G1 требуется больше ресурсов ЦП для работы параллельно с основной программой, что снижает пропускную способность приложения.
Плюсы: работает лучше, чем CMS. Паузы короче.
Минусы: потребляет больше процессора. Он потребляет больше памяти, если у нас много довольно больших объектов (более 500 КБ), потому что он помещает такие объекты в один регион (1-32 МБ)
Эпсилон GC
Epsilon GC предназначен для ситуаций, когда сборка мусора не требуется.
Epsilon GC не выполняет сборку мусора. Он использует TLAB (локальные буферы выделения потока) для выделения новых объектов — небольших буферов памяти, запрашиваемых отдельными потоками из кучи. Огромные объекты, которые не помещаются в буфер, запрашивают блоки памяти специально для них.
Когда Epsilon GC исчерпывает ресурсы, генерируется OutOfMemoryError, и процесс завершается.
К преимуществам Epsilon GC относятся меньшие накладные расходы и более быстрое выделение памяти для приложений, создающих все необходимые объекты при запуске, или запускающих кратковременные приложения, не использующие всю выделенную память.
Epsilon GC также может помочь проанализировать накладные расходы, которые другие сборщики мусора приносят вашему приложению.
Плюсы: очень быстро.
Минусы: не собирает предметы :)
Следующие два коллектора являются самыми передовыми в своем роде, а также самыми сложными. Поэтому рассмотрим их кратко.
ЗГК
ZGC стремится поддерживать паузы на уровне доли миллисекунды даже при работе с огромными объемами данных.
ZGC — это сборщик мусора, разработанный Oracle для Java, который обеспечивает высокую пропускную способность и низкую задержку при обработке больших куч (до 16 ТБ).
ZGC основан на принципах виртуальной памяти и использует раскраску указателя для отслеживания состояния объектов во время сборки мусора.
Плюсы: паузы менее миллисекунды, даже в больших кучах, полезны для приложений, требующих короткого времени обработки запросов. Он работает с очень большими кучами с хорошей пропускной способностью. ZGC может сжимать динамическую память во время сборки мусора
Минусы: высокая загрузка ЦП и первоначальные накладные расходы, поскольку ZGC имеет относительно высокие начальные накладные расходы, которые могут замедлить время запуска приложений.
Шенандоа GC
Shenandoah GC — еще один сборщик мусора, стремящийся к коротким паузам независимо от размера кучи.
Shenandoah GC — это сборщик мусора с малым временем паузы, разработанный Red Hat. Он предназначен для минимизации времени, затрачиваемого приложением на остановку своего выполнения во время сборки мусора.
Как и ZGC, это параллельный сборщик, что означает, что он работает, пока приложение все еще работает, сводя к минимуму паузы.
Shenandoah GC использует «указатели пересылки» для перемещения объектов во время сборки мусора. И метод под названием "устранение барьера нагрузки" для повышения производительности.
Плюсы: паузы. Shenandoah GC может достичь короткого времени паузы, часто менее 10 мс, даже для массивных куч. Перспективная пропускная способность.
Минусы: высокая загрузка ЦП и сложность - у него неожиданные подходы к работе при больших нагрузках.
Сборщики мусора — одна из самых сложных задач в программировании. В этом направлении постоянно ведутся научные исследования. Разработчики очень редко прибегают к настройке GC. Но поверхностно знать, как работает ваш инструмент, все же необходимо.
Спасибо за внимание.
Оригинал