Какой сборщик мусора никогда не приостанавливает работу приложения
Я нашел некоторую информацию об сборщике мусора Android, которые противоречат мне.
В руководстве Android Devevelopers сказано:
Android 3.0 - первая версия платформы, предназначенная для запуска либо одноядерные, либо многоядерные архитектуры процессоров. Разнообразие изменения в Dalvik VM, Bionic library и в других местах добавляют поддержку для симметричной многопроцессорности в многоядерных средах. Эти оптимизация может принести пользу всем приложениям, даже тем, которые однопоточный. Например, с двумя активными сердечниками однопоточный приложение может по-прежнему видеть повышение производительности, если мусор Dalvik коллектор работает на втором ядре. Система обеспечит это автоматически ".
Хорошо, теперь другая вещь
Согласно этой ссылке: Архитектура виртуальной машины Dalvik андроид использует маркер и развертку aproach.
Текущая стратегия в сборщике мусора Dalvik заключается в том, чтобы сохранить отметку бит или биты, указывающие, что конкретный объект "достижимый", и поэтому не следует собирать мусор, разделить из другой памяти кучи.
Если мы проверим, как эта метка и развертка работают по этой ссылке: Отметить и отладить алгоритм сбора мусора , мы можем видеть это:
Основным недостатком подхода mark-and-sweep является тот факт, что что обычное выполнение программы приостанавливается, пока мусор выполняется алгоритм сбора. В частности, это может быть проблемой в программа, которая взаимодействует с пользователем пользователя или которая должна удовлетворять ограничения выполнения в реальном времени. Например, интерактивный приложение, использующее сбор мусора маркировки и очистки периодически не реагирует.
Итак, теперь мой вопрос: как это работает? Собирает ли сборщик мусора все, пока он работает, или он может работать полностью независимо от другого активного ядра процессора?
ОТВЕТЫ
Ответ 1
В драйвере Dalvik в версии Gingerbread и выше используется сборщик мусора Чаще всего параллельный сборщик с периодом паузы, обычно около 5 мс. Поэтому да, GC влияет на другие приложения, останавливая их, но алгоритм параллельного GC способен минимизировать эти паузы.
Вы должны посмотреть:
В целом, теория коллекции мусора [Вики-сборник мусора] объясняет:
Стоп-мир сборщики мусора полностью останавливают выполнение программы для запуска цикла сбора
Инкрементные и совпадающие сборщики мусора предназначены для уменьшения этого нарушения перемежая их работу с активностью из основной программы. Инкрементные сборщики мусора выполнять цикл сбора мусора в дискретных фазах, причем выполнение программы допускается между каждая фаза (а иногда и на некоторых фазах).
Ответ 2
Ответ 3
Он не будет останавливать другие приложения, это может приостановить ваше приложение. Знак и развертка не должны останавливать всю обработку, это просто самый простой способ сделать это. Вероятно, у него есть некоторые моменты, когда он приостанавливает выполнение, а другой - нет. Единственный реальный способ рассказать - это посмотреть на код Dalvik VM. И я не буду рассчитывать на то, что это тот же ответ во всех версиях Android.
Сегодня мы продолжаем цикл статей о сборщиках мусора, поставляемых с виртуальной машиной Oracle Java HotSpot VM. Мы уже изучили немного теории и рассмотрели, каким образом с кучей расправляются два базовых сборщика — Serial GC и Parallel GC. А в этой статье речь пойдет о сборщиках CMS GC и G1 GC, первостепенной задачей которых является минимизация пауз при наведении порядка в памяти приложений, оперирующих средними и большими объемами данных, то есть по большей части в памяти серверных приложений.
Два этих сборщика объединяют общим названием «mostly concurrent collectors», то есть «по большей части конкурентные сборщики». Это связано с тем, что часть своей работы они выполняют параллельно с основными потоками приложения, то есть в какие-то моменты конкурируют с ними за ресурсы процессора. Конечно, это не проходит бесследно, и в итоге они разменивают улучшение в части пауз на ухудшение в части пропускной способности. Хотя делают это по-разному. Давайте посмотрим, как.
Использование CMS GC включается опцией -XX:+UseConcMarkSweepGC.
Принципы работы
Мы уже встречали слова Mark и Sweep при рассмотрении последовательного и параллельного сборщиков (если вы не встречали, то сейчас как раз самое время это сделать). Они обозначали два шага в процессе сборки мусора в старшем поколении: пометку выживших объектов и удаление мертвых объектов. Сборщик CMS получил свое название благодаря тому, что выполняет указанные шаги параллельно с работой основной программы.
При этом CMS GC использует ту же самую организацию памяти, что и уже рассмотренные Serial / Parallel GC: регионы Eden + Survivor 0 + Survivor 1 + Tenured и такие же принципы малой сборки мусора. Отличия начинаются только тогда, когда дело доходит до полной сборки. В случае CMS ее называют старшей (major) сборкой, а не полной, так как она не затрагивает объекты младшего поколения. В результате, малая и старшая сборки здесь всегда разделены. Одним из побочных эффектов такого разделения является то, что все объекты младшего поколения (даже потенциально мертвые) могут играть роль корней при определении статуса объектов в старшем поколении.
Важным отличием сборщика CMS от рассмотренных ранее является также то, что он не дожидается заполнения Tenured для того, чтобы начать старшую сборку. Вместо этого он трудится в фоновом режиме постоянно, пытаясь поддерживать Tenured в компактном состоянии.
Давайте рассмотрим, что из себя представляет старшая сборка мусора при использовании CMS GC.
Начинается она с остановки основных потоков приложения и пометки всех объектов, напрямую доступных из корней. После этого приложение возобновляет свою работу, а сборщик параллельно с ним производит поиск всех живых объектов, доступных по ссылкам из тех самых помеченных корневых объектов (эту часть он делает в одном или в нескольких потоках).
Естественно, за время такого поиска ситуация в куче может поменяться, и не вся информация, собранная во время поиска живых объектов, оказывается актуальной. Поэтому сборщик еще раз приостанавливает работу приложения и просматривает кучу для поиска живых объектов, ускользнувших от него за время первого прохода. При этом допускается, что в живые будут записаны объекты, которые на время окончания составления списка таковыми уже не являются. Эти объекты называются плавающим мусором (floating garbage), они будут удалены в процессе следующей сборки.
После того, как живые объекты помечены, работа основных потоков приложения возобновляется, а сборщик производит очистку памяти от мертвых объектов в нескольких параллельных потоках. При этом следует иметь в виду, что после очистки не производится упаковка объектов в старшем поколении, так как делать это при работающем приложении весьма затруднительно.
Сборщик CMS достаточно интеллектуальный. Например, он старается разносить во времени малые и старшие сборки мусора, чтобы они совместно не создавали продолжительных пауз в работе приложения (дополнительные подробности об этом разнесении в комментариях). Для этого он ведет статистику по прошедшим сборкам и исходя из нее планирует последующие.
Отдельно следует рассмотреть ситуацию, когда сборщик не успевает очистить Tenured до того момента, как память полностью заканчивается. В этом случае работа приложения останавливается, и вся сборка производится в последовательном режиме. Такая ситуация называется сбоем конкурентного режима (concurrent mode failure). Сборщик сообщает нам об этих сбоях при включенных опциях -verbose:gc или -Xloggc:filename.
У CMS есть один интересный режим работы, называемый Incremental Mode, или i-cms, который заставляет его временно останавливаться при выполнении работ параллельно с основным приложением, чтобы на короткие периоды высвобождать ресурсы процессора (что-то вроде АБС у автомобиля). Это может быть полезным на машинах с малым количеством ядер. Но данный режим уже помечен как не рекомендуемый к применению и может быть отключен в будущих релизах, поэтому подробно его разбирать не будем.
Ситуации STW
- Малая сборка мусора. Эта пауза ничем не отличается от аналогичной паузы в Parallel GC.
- Начальная фаза поиска живых объектов при старшей сборке (так называемая initial mark pause). Эта пауза обычно очень короткая.
- Фаза дополнения набора живых объектов при старшей сборке (известная также как remark pause). Она обычно длиннее начальной фазы поиска.
Настройка
Так как подходы к организации памяти у CMS аналогичны используемым в Serial / Parallel GC, для него применимы те же опции определения размеров регионов кучи, а также опции автоматической подстройки под требуемые параметры производительности.
Обычно CMS, основываясь на собираемой статистике о поведении приложения, сам определяет, когда ему выполнять старшую сборку, но у него также есть порог наполненности региона Tenured, при достижении которого должна обязательно быть инициирована старшая сборка. Этот порог можно задать с помощью опции , значение указывается в процентах. Значение -1 (иногда устанавливается по умолчанию) указывает на отключение сборки по такому условию.
Достоинства и недостатки
Достоинством данного сборщика по сравнению с рассмотренными ранее Serial / Parallel GC является его ориентированность на минимизацию времен простоя, что является критическим фактором для многих приложений. Но для выполнения этой задачи приходится жертвовать ресурсами процессора и зачастую общей пропускной способностью.
Вспомним еще, что данный сборщик не уплотняет объекты в старшем поколении, что приводит к фрагментации Tenured. Этот факт в совокупности с наличием плавающего мусора приводит к необходимости выделять приложению (конкретно — старшему поколению) больше памяти, чем потребовалось бы для других сборщиков (Oracle советует на 20% больше).
Ну и долгие паузы при потенциально возможных сбоях конкурентного режима могут стать неприятным сюрпризом. Хотя они не частые, и при наличии достаточного объема памяти CMS’у удается их полностью избегать.
Тем не менее, такой сборщик может подойти приложениям, использующим большой объем долгоживущих данных. В этом случае некоторые его недостатки нивелируются. Но в любом случае, не стоит принимать решение о его использовании пока вы не познакомились с еще одним сборщиком в обойме Java HotSpot VM.
Вот мы и добрались до последнего и наверняка самого интересного для многих сборщика мусора — G1 (что является сокращением от Garbage First). Интересен он прежде всего тем, что не является явным продолжением линейки Serial / Parallel / CMS, добавляющим параллельность еще в какую-нибудь фазу сборки мусора, а использует уже существенно отличающийся подход к задаче очистки памяти.
G1 — самый молодой в составе сборщиков мусора виртуальной машины HotSpot. Он изначально позиционировался как сборщик для приложений с большими кучами (от 4 ГБ и выше), для которых важно сохранять время отклика небольшим и предсказуемым, пусть даже за счет уменьшения пропускной способности. На этом поле он конкурировал с CMS GC, хотя изначально и не так успешно, как хотелось бы. Но постепенно он исправлялся, улучшался, стабилизировался и, наконец, достиг такого уровня, что Oracle говорит о нем как о долгосрочной замене CMS, а в Open JDK даже серьезно рассматривают его на роль сборщика по умолчанию для серверных конфигураций в 9-й версии.
Это все явно стоит того, чтобы разобраться с его устройством. Не будем же откладывать.
G1 включается опцией Java -XX:+UseG1GC.
Принципы работы
Первое, что бросается в глаза при рассмотрении G1 — это изменение подхода к организации кучи. Здесь память разбивается на множество регионов одинакового размера. Размер этих регионов зависит от общего размера кучи и по умолчанию выбирается так, чтобы их было не больше 2048, обычно получается от 1 до 32 МБ. Исключение составляют только так называемые громадные (humongous) регионы, которые создаются объединением обычных регионов для размещения очень больших объектов.
Разделение регионов на Eden, Survivor и Tenured в данном случае логическое, регионы одного поколения не обязаны идти подряд и даже могут менять свою принадлежность к тому или иному поколению. Пример разделения кучи на регионы может выглядеть следующим образом (количество регионов сильно приуменьшено):
Малые сборки выполняются периодически для очистки младшего поколения и переноса объектов в регионы Survivor, либо их повышения до старшего поколения с переносом в Tenured. Над переносом объектов трудятся несколько потоков, и на время этого процесса работа основного приложения останавливается. Это уже знакомый нам подход из рассмотренных ранее сборщиков, но отличие состоит в том, что очистка выполняется не на всем поколении, а только на части регионов, которые сборщик сможет очистить не превышая желаемого времени. При этом он выбирает для очистки те регионы, в которых, по его мнению, скопилось наибольшее количество мусора и очистка которых принесет наибольший результат. Отсюда как раз название Garbage First — мусор в первую очередь.
- Initial mark. Пометка корней (с остановкой основного приложения) с использованием информации, полученной из малых сборок.
- Concurrent marking. Пометка всех живых объектов в куче в нескольких потоках, параллельно с работой основного приложения.
- Remark. Дополнительный поиск не учтенных ранее живых объектов (с остановкой основного приложения).
- Cleanup. Очистка вспомогательных структур учета ссылок на объекты и поиск пустых регионов, которые уже можно использовать для размещения новых объектов. Первая часть этого шага выполняется при остановленном основном приложении.
После окончания цикла пометки G1 переключается на выполнение смешанных сборок. Это значит, что при каждой сборке к набору регионов младшего поколения, подлежащих очистке, добавляется некоторое количество регионов старшего поколения. Количество таких сборок и количество очищаемых регионов старшего поколения выбирается исходя из имеющейся у сборщика статистики о предыдущих сборках таким образом, чтобы не выходить за требуемое время сборки. Как только сборщик очистил достаточно памяти, он переключается обратно в режим малых сборок.
Очередной цикл пометки и, как следствие, очередные смешанные сборки будут запущены тогда, когда заполненность кучи превысит определенный порог.
Смешанная сборка мусора в приведенном выше примере кучи может пройти вот так:
Может оказаться так, что в процессе очистки памяти в куче не остается свободных регионов, в которые можно было бы копировать выжившие объекты. Это приводит к возникновению ситуации allocation (evacuation) failure, подобие которой мы видели в CMS. В таком случае сборщик выполняет полную сборку мусора по всей куче при остановленных основных потоках приложения.
Опираясь на уже упомянутую статистику о предыдущих сборках, G1 может менять количество регионов, закрепленных за определенным поколением, для оптимизации будущих сборок.
Гиганты
- Он никогда не перемещается между регионами.
- Он может удаляться в рамках цикла пометки или полной сборки мусора.
- В регион, занятый громадным объектом, больше никого не подселяют, даже если в нем остается свободное место.
В продолжении данного цикла статей мы посмотрим, как с этим можно бороться.
Ситуации STW
- Процессы переноса объектов между поколениями. Для минимизации таких пауз G1 использует несколько потоков.
- Короткая фаза начальной пометки корней в рамках цикла пометки.
- Более длинная пауза в конце фазы remark и в начале фазы cleanup цикла пометки.
Настройка
Так как основной целью сборщика G1 является минимизация пауз в работе основного приложения, то и главной опцией при его настройке можно считать уже встречавшуюся нам , задающую приемлемое для нас максимальное время разовой сборки мусора. Даже если вы не собираетесь задавать это свойство, хотя бы проверьте его значение по умолчанию. Хотя в документации Oracle и говориться, что по умолчанию время сборки не ограничено, но по факту это не всегда так.
Опции и задают количество потоков, которые будут использоваться для сборки мусора и для выполнения цикла пометок соответственно.
Если вас не устраивает автоматический выбор размера региона, вы можете задать его вручную с помощью опции . Значение должно быть степенью двойки, если мерить в мегабайтах. Например, .
При желании можно изменить порог заполненности кучи, при достижении которого инициируется выполнение цикла пометок и переход в режим смешанных сборок. Это делается опцией , принимающей значение в процентах. По умолчанию, этот порог равен 45%.
Если же вы решите залезть в дебри настроек G1 по-глубже, то можете включить дополнительные функции опциями и и поиграть с экспериментальными настройками.
Достоинства и недостатки
В целом считается, что сборщик G1 более аккуратно предсказывает размеры пауз, чем CMS, и лучше распределяет сборки во времени, чтобы не допустить длительных остановок приложения, особенно при больших размерах кучи. При этом он лишен и некоторых других недостатков CMS, например, он не фрагментирует память.
Расплатой за достоинства G1 являются ресурсы процессора, которые он использует для выполнения достаточно большой части своей работы параллельно с основной программой. В результате страдает пропускная способность приложения. Целевым значением пропускной способности по умолчанию для G1 является 90%. Для Parallel GC, например, это значение равно 99%. Это, конечно, не значит, что пропускная способность с G1 всегда будет почти на 10% меньше, но данную особенность следует всегда иметь в виду.
Вот мы и разобрали алгоритмы работы всех четырех сборщиков мусора в виртуальной машине HotSpot. В следующей статье попробуем разобраться, каким образом эти знания можно применять для оптимизации работы приложений.
В среде CLR сборщик мусора выполняет функции автоматического диспетчера памяти. Сборщик мусора управляет выделением и освобождением памяти для приложения. Следовательно, разработчикам, работающим с управляемым кодом, не нужно писать код для выполнения задач по управлению памятью. Автоматическое управление памятью позволяет устранить распространенные проблемы, которые связаны с утечкой памяти из-за того, что объект не был освобожден, или попыткой доступа к памяти для объекта, который был освобожден.
В этой статье описаны основные понятия сборки мусора.
Преимущества
Использование сборщика мусора обеспечивает следующие преимущества:
Разработчикам не нужно освобождать память вручную.
Эффективно выделяет память для объектов в управляемой куче.
Уничтожает объекты, которые больше не используются, очищает их память и сохраняет память доступной для будущих распределений. Управляемые объекты автоматически получают чистое содержимое, поэтому конструкторам не нужно инициализировать каждое поле данных.
Обеспечивает безопасность памяти, гарантируя, что объект не сможет использовать содержимое другого объекта.
Основы работы с памятью
В следующем списке перечислены важные понятия памяти среды CLR.
Каждый процесс имеет свое собственное отдельное виртуальное адресное пространство. Все процессы на одном компьютере совместно используют одну и ту же физическую память и один файл подкачки, если он есть.
По умолчанию на 32-разрядных компьютерах каждому процессу выделяется 2 Гбайт виртуального адресного пространства в пользовательском режиме.
Разработчики приложений работают только с виртуальным адресным пространством и никогда не управляют физической памятью напрямую. Сборщик мусора выделяет и освобождает виртуальную память для разработчика в управляемой куче.
При написании машинного кода для работы с виртуальным адресным пространством используются функции Windows. Эти функции выделяют и освобождают виртуальную память для разработчика в собственных кучах.
Виртуальная память может находиться в трех состояниях.
Виртуальное адресное пространство может стать фрагментированным. Это означает, что в адресном пространстве находятся свободные блоки, также известные как пропуски. Когда производится запрос на выделение виртуальной памяти, диспетчер виртуальной памяти должен найти один свободный блок достаточного размера для выполнения этого запроса на выделение. Даже если в системе есть 2 ГБ свободного пространства, операция выделения 2 ГБ завершится неудачей, если это пространство не расположено в одном адресном блоке.
Память может закончиться, если будет недостаточно виртуального адресного пространства для резервирования или физического пространства для выделения.
Файл подкачки используется, даже если нехватка физической памяти (то есть потребность в физической памяти) невелика. При первом возникновении нехватки физической памяти операционная система должна освободить пространство в физической памяти для хранения данных, для чего она производит резервное копирование некоторых данных, находящихся в физической памяти, в файл подкачки. Эти данные не выгружаются, пока в этом нет необходимости, так что с подкачкой можно столкнуться в ситуациях с небольшой нехваткой физической памяти.
Выделение памяти
При инициализации нового процесса среда выполнения резервирует для него непрерывную область адресного пространства. Это зарезервированное адресное пространство называется управляемой кучей. Эта управляемая куча содержит указатель адреса, с которого будет выделена память для следующего объекта в куче. Изначально этот указатель устанавливается в базовый адрес управляемой кучи. Все ссылочные типы размещаются в управляемой куче. Когда приложение создает первый ссылочный тип, память для него выделяется, начиная с базового адреса управляемой кучи. При создании приложением следующего объекта сборщик мусора выделяет для него память в адресном пространстве, непосредственно следующем за первым объектом. Пока имеется доступное адресное пространство, сборщик мусора продолжает выделять пространство для новых объектов по этой схеме.
Выделение памяти из управляемой кучи происходит быстрее, чем неуправляемое выделение памяти. Так как среда выполнения выделяет память для объекта путем добавления значения к указателю, это осуществляется почти так же быстро, как выделение памяти из стека. Кроме того, поскольку выделяемые последовательно новые объекты располагаются в управляемой куче непрерывно, приложение может быстро получать доступ к ним.
Освобождение памяти
Механизм оптимизации сборщика мусора определяет наилучшее время для выполнения сбора, основываясь на произведенных выделениях памяти. Когда сборщик мусора выполняет очистку, он освобождает память, выделенную для объектов, которые больше не используются приложением. Он определяет, какие объекты больше не используются, анализируя корни приложения. Корни приложения содержат статические поля, локальные переменные в стеке потока, регистры процессора, дескрипторы сборки мусора и очередь завершения. Каждый корень либо ссылается на объект, находящийся в управляемой куче, либо имеет значение NULL. Сборщик мусора может запросить остальную часть среды выполнения для этих корней. С помощью этого списка он проверяет корни приложения и при этом создает граф, содержащий все объекты, к которым можно получить доступ из этих корней.
Объекты, не входящие в этот граф, являются недостижимыми из данных корней приложения. Сборщик мусора считает недостижимые объекты мусором и освобождает выделенную для них память. В процессе очистки сборщик мусора проверяет управляемую кучу, отыскивая блоки адресного пространства, занятые недостижимыми объектами. При обнаружении недостижимого объекта он использует функцию копирования памяти для уплотнения достижимых объектов в памяти, освобождая блоки адресного пространства, выделенные под недостижимые объекты. После уплотнения памяти, занимаемой достижимыми объектами, сборщик мусора вносит необходимые поправки в указатель, чтобы корни приложения указывали на новые расположения объектов. Он также устанавливает указатель управляемой кучи в положение после последнего достижимого объекта.
Память уплотняется, только если при очистке обнаруживается значительное число недостижимых объектов. Если после сборки мусора все объекты в управляемой куче остаются на месте, то уплотнение памяти не требуется.
Для повышения производительности среда выполнения выделяет память для больших объектов в отдельной куче. Сборщик мусора автоматически освобождает память, выделенную для больших объектов. Но для устранения перемещений в памяти больших объектов эта память обычно не сжимается.
Условия для сборки мусора
Сборка мусора возникает при выполнении одного из следующих условий:
Объем памяти, используемой объектами, выделенными в управляемой куче, превышает допустимый порог. Этот порог непрерывно корректируется во время выполнения процесса.
вызывается метод GC.Collect . Практически во всех случаях вызов этого метода не потребуется, так как сборщик мусора работает непрерывно. Этот метод в основном используется для уникальных ситуаций и тестирования.
Управляемая куча
После инициализации средой CLR сборщик мусора выделяет сегмент памяти для хранения объектов и управления ими. Эта память называется управляемой кучей в отличие от собственной кучи операционной системы.
Управляемая куча создается для каждого управляемого процесса. Все потоки в процессе выделяют память для объектов в одной и той же куче.
Для резервирования памяти сборщик мусора вызывает функцию Windows VirtualAlloc и резервирует для управляемых приложений по одному сегменту памяти за раз. Сборщик мусора также резервирует сегменты по мере необходимости и возвращает операционной системе освобожденные сегменты (очистив их от всех объектов), вызывая функцию Windows VirtualFree.
Размер сегментов, выделенных сборщиком мусора, зависит от реализации и может быть изменен в любое время, в том числе при периодических обновлениях. Приложение не должно делать никаких допущений относительно размера определенного сегмента, полагаться на него или пытаться настроить объем памяти, доступный для выделения сегментов.
Чем меньше объектов распределено в куче, тем меньше придется работать сборщику мусора. При размещении объектов не используйте округленные значения, превышающие фактические потребности, например не выделяйте 32 байта, когда необходимо только 15 байтов.
Активированный процесс сборки мусора освобождает память, занятую неиспользуемыми объектами. Процесс освобождения сжимает используемые объекты, чтобы они перемещались вместе, и удаляет пространство, занятое неиспользуемыми объектами, уменьшая, таким образом, кучу. Это гарантирует, что объекты, распределенные совместно, останутся в управляемой куче рядом, чтобы сохранить локальность.
Степень вмешательства (частота и длительность) сборок мусора зависит от числа распределений и сохранившейся в управляемой куче памяти.
Кучу можно рассматривать как совокупность двух куч: куча больших объектов и куча маленьких объектов. Куча больших объектов содержит объекты размером от 85 000 байтов, обычно представленные массивами. Экземпляр объекта редко бывает очень большим.
Вы можете настроить пороговый размер для объектов, помещаемых в кучу больших объектов.
Поколения
Алгоритм сборки мусора учитывает следующее:
- Уплотнять память для части управляемой кучи быстрее, чем для всей кучи.
- У новых объектов время жизни меньше, а старых больше.
- Новые объекты теснее связаны друг с другом, и приложение обращается к ним приблизительно в одно и то же время.
Сборка мусора в основном сводится к уничтожению короткоживущих объектов с небольшим временем жизни. Для оптимизации производительности сборщика мусора управляемая куча делится на три поколения: 0, 1 и 2. Следовательно, объекты с большим и небольшим временем жизни обрабатываются отдельно. Сборщик мусора хранит новые объекты в поколении 0. Уровень объектов, созданных на раннем этапе работы приложения и оставшихся после сборок мусора, повышается, и они сохраняются в поколении 1 и 2. Так как сжать часть управляемой кучи быстрее, чем всю кучу, эта схема позволяет сборщику мусора освобождать память в определенном поколении, а не для всей кучи при каждой сборке мусора.
Поколение 0. Это самое молодое поколение содержит короткоживущие объекты. Примером короткоживущего объекта является временная переменная. Сборка мусора чаще всего выполняется в этом поколении.
Вновь распределенные объекты образуют новое поколение объектов и неявно являются сборками поколения 0. Однако если это большие объекты, то они попадают в кучу больших объектов, которая иногда называется поколением 3. Поколение 3 — это физическое поколение, которое логически собирается как часть поколения 2.
Большинство объектов уничтожается при сборке мусора для поколения 0 и не доживает до следующего поколения.
Если приложение пытается создать новый объект, когда поколение 0 заполнено, сборщик мусора выполняет сбор, чтобы попытаться освободить адресное пространство для объекта. Сборщик мусора начинает проверять объекты в поколении 0, а не все объекты в управляемой куче. Сборка мусора только в поколении 0 зачастую освобождает достаточно памяти для того, чтобы приложение могло и дальше создавать новые объекты.
Поколение 1. Это поколение содержит коротко живущие объекты и служит буфером между короткоживущими и долгоживущими объектами.
Когда сборщик мусора выполняет сборку для поколения 0, память уплотняется для достижимых объектов и они продвигаются в поколение 1. Так как объекты, оставшиеся после сборки, обычно склонны к долгой жизни, имеет смысл продвинуть их в поколение более высокого уровня. Сборщику мусора необязательно выполнять повторную проверку объектов поколений 1 и 2 при каждой сборке мусора поколения 0.
Если сборка поколения 0 не освобождает достаточно памяти, чтобы приложение могло создать новый объект, сборщик мусора может выполнить сборку мусора поколения 1, а затем поколения 2. Объекты в поколении 1, оставшиеся после сборок, продвигаются в поколение 2.
Поколение 2. Это поколение содержит долгоживущие объекты. Примером долгоживущих объектов служит объект в серверном приложении, содержащий статические данные, которые существуют в течение длительности процесса.
Объекты в поколении 2, оставшиеся после сборки, находятся там до тех пор, пока они не станут недостижимыми в следующей сборке.
Объекты в куче больших объектов (иногда называемой поколением 3) также собираются в поколении 2.
Сборки мусора выполняются для конкретных поколений при выполнении соответствующих условий. Сборка поколения означает сбор объектов в этом поколении и во всех соответствующих младших поколениях. Сборка мусора поколения 2 также называется полной сборкой, так как при этом уничтожаются объекты во всех поколениях (то есть все объекты в управляемой куче).
Выживание и переходы
Объекты, которые не уничтожаются при сборке мусора, называются выжившими объектами и переходят в следующее поколение.
- Объекты, оставшиеся после сборки мусора поколения 0, подвигаются в поколение 1.
- Объекты, оставшиеся после сборки мусора поколения 1, подвигаются в поколение 2.
- Объекты, оставшиеся после сборки мусора поколения 2, остаются в поколении 2.
Когда сборщик мусора обнаруживает высокую долю выживания в поколении, он повышает порог распределений для этого поколения. При следующей сборке мусора освобождается заметная часть занятой памяти. В среде CLR непрерывно контролируется равновесие двух приоритетов: не позволить рабочему набору приложения стать слишком большим, задерживая сборку мусора, и не позволить сборке мусора выполняться слишком часто.
Эфемерные поколения и сегменты
Так как объекты в поколениях 0 и 1 являются короткоживущими, эти поколения называются эфемерными поколениями.
Эфемерные поколения выделяются в сегменте памяти, который называется эфемерным сегментом. Каждый новый сегмент, полученный сборщиком мусора, становится новым эфемерным сегментом и содержит объекты, пережившие сборку мусора для поколения 0. Старый эфемерный сегмент становится новым сегментом поколения 2.
Размер эфемерного сегмента зависит от того, является ли система 32- или 64-разрядной, и от типа сборщика мусора (сборка мусора рабочей станции или сервера). В следующей таблице показаны размеры эфемерного сегмента по умолчанию.
Сборка мусора рабочей станции и сервера | 32-разрядная версия | 64-разрядная версия |
---|---|---|
Сборщик мусора рабочей станции | 16 МБ | 256 МБ |
Сборщик мусора сервера | 64 МБ | 4 Гбайт |
Сборщик мусора сервера с более чем 4 логическими ЦП | 32 МБ | 2 ГБ |
Сборщик мусора сервера с более чем 8 логическими ЦП | 16 МБ | 1 ГБ |
Этот эфемерный сегмент может содержать объекты поколения 2. Объекты поколения 2 могут использовать несколько сегментов (столько, сколько требуется процессу и сколько разрешает память).
Объем памяти, освобождаемой при эфемерной сборке мусора, ограничен размером эфемерного сегмента. Освобождаемый объем памяти пропорционален пространству, занятому неиспользуемыми объектами.
Процесс сборки мусора
Сборка мусора состоит из следующих этапов:
Этап маркировки, выполняющий поиск всех используемых объектов и составляющий их перечень.
Этап перемещения, обновляющий ссылки на сжимаемые объекты.
Этап сжатия, освобождающий пространство, занятое неиспользуемыми объектами и сжимающий выжившие объекты. На этапе сжатия объекты, пережившие сборку мусора, перемещаются к более старому концу сегмента.
Так как сборки поколения 2 могут занимать несколько сегментов, объекты, перешедшие в поколение 2, могут быть перемещены в более старый сегмент. Выжившие объекты поколений 1 и 2 могут быть перемещены в другой сегмент, так как они перешли в поколение 2.
- Предельный объем памяти для контейнера.
- Параметр конфигурации среды выполнения GCHeapHardLimit или GCHeapHardLimitPercent.
Чтобы определить, являются ли объекты используемыми, сборщик мусора задействует следующие сведения.
Корни стека. Переменные стека, предоставленные JIT-компилятором и средством обхода стека. JIT-оптимизация позволяет уменьшить или увеличить области кода, в которых переменные стека сообщаются сборщику мусора.
Дескрипторы сборки мусора. Дескрипторы, которые указывают на управляемые объекты и которые могут быть выделены пользовательским кодом или средой CLR.
Статические данные. Статические объекты в доменах приложений, которые могут ссылаться на другие объекты. Каждый домен приложения следит за своими статическими объектами.
Перед запуском сборки мусора все управляемые потоки, кроме потока, запустившего сборку мусора, приостанавливаются.
На следующем рисунке показан поток, запускающий сборку мусора и вызывающий приостановку других потоков.
Неуправляемые ресурсы
Для большинства объектов, созданных приложением, сборщик мусора автоматически выполнит необходимые задачи по управлению памятью. Однако для неуправляемых ресурсов требуется явная очистка. Основным типом неуправляемых ресурсов являются объекты, образующие упаковку для ресурсов операционной системы, такие как дескриптор файлов, дескриптор окна или сетевое подключение. Хотя сборщик мусора может отслеживать время жизни управляемого объекта, инкапсулирующего неуправляемый ресурс, он не знает, как освобождать эти ресурсы.
При создании объекта, инкапсулирующего неуправляемый ресурс, рекомендуется предоставлять необходимый код для очистки неуправляемого ресурса в общем методе Dispose . Предоставление метода Dispose дает возможность пользователям объекта явно освобождать память при завершении работы с объектом. Когда используется объект, инкапсулирующий неуправляемый ресурс, вызовите Dispose при необходимости.
Работа программы неизбежно потребует ресурсов. Если недействительные ресурсы объекта не будут обработаны вовремя, они всегда будут занимать память, что в конечном итоге приведет к ее переполнению. Поэтому управление памятью очень важно.
Общие алгоритмы сборки мусора
Подсчет ссылок
Принцип: если есть объект A, любой объект ссылается на A, то счетчик ссылок объекта A увеличивается на 1, когда ссылка не выполняется, счетчик ссылок равен -1, а когда значение счетчика объекта A равно 0 В данный момент объект A не упоминается и может быть переработан.
преимущество:
1. Производительность в реальном времени высока. Вам не нужно ждать, пока памяти не хватит, чтобы начать перезапись. Вы можете напрямую освободить ее в зависимости от того, равен ли счетчик объектов 0 во время выполнения.
2, приложение не нужно приостанавливать во время сборки мусора.
3. Региональность. Когда счетчик объекта обновляется, затрагивается только объект, а глобальное сканирование не выполняется
Недостатки:
1. Каждый раз, когда на объект ссылаются, счетчик должен обновляться, что требует небольших временных затрат.
2. Тратить впустую ресурсы процессора, даже если памяти достаточно, по-прежнему запускайте счетчик памяти.
3, невозможно решить циклическую зависимость (самый большой недостаток)
Круговая зависимость:
Марк развернуть
Метод удаления тега разделяет сборку мусора на два этапа, а именно тегирование и очистку.
Тег : отметьте ссылочный объект из корневого узла
Очистить: неотмеченные объекты являются объектами мусора.
принцип:
На этом рисунке представлено состояние всех объектов во время работы программы, их биты флагов все равны 0 (то есть не отмечены, следующее значение по умолчанию 0 означает немаркировано, 1 означает отмечено). что эффективное пространство памяти в это время исчерпано, JVM остановит приложение и запустит поток сборки мусора, а затем начнет работу по маркировке.В соответствии с алгоритмом корневого поиска после маркировки состояние объекта будет следующим.
Видно, что в соответствии с алгоритмом корневого поиска все объекты, доступные из корневого объекта, помечаются как уцелевшие, и на этом первый этап маркировки завершен. Далее нам нужно выполнить второй этап очистки.После очистки оставшиеся объекты выглядят так, как показано на рисунке ниже;
Удаление тега решает проблему повторяющихся ссылок.
Но недостатки также очевидны:
1. Эффективность низкая. Два действия - пометка и очистка - должны пройти по всем объектам и прекратить ссылаться на программу во время сборки мусора. Работа с приложениями с высокими требованиями к интерактивности будет очень хуже.
2. Память, очищаемая алгоритмом очистки меток, более фрагментирована, так как переработанные объекты могут существовать в каждом углу, поэтому очищенная память несовместима.
Отметить сжатие
Алгоритм сжатия тега - это оптимизированный алгоритм, основанный на алгоритме удаления сжатия тега. Как и метод удаления тега, тег ссылки на объект начинается с корневого узла. На этапе очистки он Убрать немаркированные объекты непросто. Вместо этого живые объекты сжимаются до другого конца памяти. Затем уберите неожиданный мусор на границе, чтобы решить проблему фрагментации
Преимущества и недостатки:
По сравнению с методом удаления меток, он решает проблему фрагментации памяти. В то же время алгоритм сжатия меток на один шаг больше. Шаг перемещения места в памяти объекта также оказывает определенное влияние на его эффективность.
Алгоритм копирования
Суть алгоритма копирования состоит в том, чтобы разделить пространство памяти на два и использовать каждый раз только одно из них. Во время сборки мусора скопируйте используемый объект в другое пространство памяти, а затем Очистите пространство памяти, поменяйте местами две памяти и завершите сборку мусора.
Этот тип подходящей памяти содержит больше объектов мусора, меньше объектов для копирования,
1 При запуске GC объект будет существовать только в области Eden и Survivor.
2. Затем будет выполнена сборка мусора. Все уцелевшие объекты в области Эдема будут скопированы в Выживший "Кому", а объекты, все еще живые в области "От", будут определены в соответствии с их возрастом значение. Когда возраст достигает определенного значения (возрастной порог может быть установлен с помощью XX: MaxTenuringThreshold), он переместится в старость, а те, которые не достигают порогового значения, переместятся в область To
3. После этого GC, From и To поменяются ролями, чтобы гарантировать, что область Survivor To пуста.
4. ГХ будет повторять этот процесс до тех пор, пока не будет заполнена область "Кому". После заполнения области "Кому" все объекты будут перемещены в старое поколение.
Преимущества и недостатки:
Когда много мусорных объектов, эффективность выше
После очистки в памяти нет фрагментации
Недостатки:
требует двух частей памяти
не подходит, когда меньше мусорных объектов.
- Алгоритм генерации:
Согласно нашему анализу выше, мы знаем, что у каждого алгоритма есть свои преимущества и недостатки, и никто не может его заменить, поэтому мы должны сделать мудрый выбор, основываясь на характеристиках объектов сборки мусора. .
Затем алгоритм генерации появляется неявно и выбирает на основе объекта, который будет переработан.В JVM молодое поколение подходит для алгоритмов копирования, а старое поколение подходит для маркировки очистки или маркировки алгоритмов сжатия.
Уборщик мусора
- Серийный сборщик мусора
относится к использованию одного потока для сборки мусора. Во время сборки мусора работает только один поток, и все потоки в ссылке java должны быть приостановлены и ждать завершения сборки мусора. Это явление называется It is STW (Stop the World).
Для высоко интерактивных приложений этот тип сборщика мусора неприемлем.
Тестовый код:
DefNew: указывает, что используется серийный сборщик мусора.
4928K-> 511K (4928K): указывает, что молодое поколение занимает 4928K памяти до GC и 511K памяти после GC.
0,0005894 секунды: время, проведенное в GC.
6949K-> 2447K (15872K): память кучи занимает 6949K, после GC она занимает 2447K, общий размер составляет 15872K
- Параллельный сборщик мусора
Улучшен параллельный сборщик мусора на основе последовательного сборщика мусора, в котором одиночный поток заменен на многопоточность для сборки мусора, что может сократить время сборки мусора. (Это относится к машинам с сильным параллелизмом)
Конечно, параллельный сборщик мусора также приостанавливает работу приложения во время процесса сборки, что аналогично последовательному сборщику мусора. Он выполняется только параллельно, что быстрее и время паузы короче.
-CMS одновременный сборщик мусора
Отметка инициализации (CMS-initial-mark), обозначающая root, вызовет stw.
Знак одновременного выполнения (CMS-concurrent-mark), который выполняется одновременно с пользовательским потоком.
предварительная очистка (CMS-concurrent-preclean), выполняемая одновременно с потоком пользователя
Замечание CMS вызовет stw
Параллельное сканирование (CMS-concurrent-sweep), которое выполняется одновременно с пользовательским потоком.
Отрегулируйте размер кучи и настройте CMS на выполнение сжатия памяти после очистки. Цель состоит в том, чтобы очистить фрагменты в памяти.
Состояние одновременного сброса ожидает следующего триггера CMS (CMS-concurrent-reset) и выполняется одновременно с потоком пользователя.
Сборщик мусора G1
Принцип разработки G1 - упростить настройку производительности JVM. Для завершения настройки разработчикам требуется всего три простых шага:
1. Первый шаг - запустить сборщик мусора G1.
2, второй шаг - установить максимальный объем памяти кучи.
3, установите максимальное время паузы
G1 предоставляет три режима сборки мусора: YoungGC, MixedGC и Full GC, которые запускаются при разных условиях.
принцип:
По сравнению с другими сборщиками, самая большая разница между сборщиком мусора G1 заключается в том, что он отменяет физическое разделение молодого поколения и старого поколения, а вместо этого разделяет кучу на несколько регионов (регионов). эти области содержат логически молодые и старые области.
Преимущество заключается в том, что нам больше не нужно отдельное пространство для установки каждого поколения. Не беспокойтесь о том, достаточно ли памяти на каждой ленте.
В области, разделенной G1, сборка мусора молодого поколения по-прежнему использует метод приостановки всех приложений. Чтобы скопировать уцелевшие объекты в пространство старого поколения или выжившего, сборщик G1 завершает работу по очистке, копируя объекты из одной области в другую.
Это означает, что в нормальном процессе G1 завершил сжатие кучи (по крайней мере, часть сжатия кучи), поэтому проблем с фрагментацией памяти cms не возникнет.
В G1 есть особая область под названием Humongous area.
1. Если пространство, занимаемое объектом, превышает 50% емкости раздела, сборщик G1 считает его гигантским объектом.
2. Эти гигантские объекты по умолчанию выделяются напрямую в старом поколении, но если это недолговечный гигантский объект, это отрицательно повлияет на сборщик мусора.
3. Чтобы решить эту проблему, G1 разделил огромную область, которая используется для хранения огромных объектов. Если одна область H не может вместить гигантский объект, G1 будет искать последовательные H-разделы для хранения. Чтобы найти непрерывную область H, иногда необходимо запустить полную сборку мусора.
YoungGC
YoungGC в основном выполняет сборку мусора в области Eden и будет запускаться, когда пространство Eden будет исчерпано.
1. Данные из пространства Eden перемещаются в пространство Survivor. Если пространства Survivor недостаточно, часть данных в пространстве Eden будет напрямую переведена в старое поколение.
2. Данные области выжившего перемещаются в новую область выжившего, а некоторые данные напрямую передаются в старое поколение.
3. Наконец, данные пространства eden пусты, сборщик мусора перестает работать, а поток приложения продолжает выполняться.
RememberedSet (запомненный набор)
Когда GC объекты в молодом поколении, как нам найти корневой объект объектов в молодом поколении?
Корневой объект может принадлежать молодому или старому поколению, как и все объекты в корне старого поколения?
Если старое поколение просканируется полностью, сканирование займет много времени.
Итак, G1 представил концепцию RSet. Его полное имя - RememberedSet, и его роль заключается в отслеживании ссылок на объекты в определенной куче.
При инициализации каждого Redion инициализируется Rset. Этот набор используется для записи и отслеживания ссылок из других регионов на объект региона. По умолчанию каждый регион разделен на несколько карт размером 512 КБ, Итак, что RSet необходимо записать, это xx Card of xx Region
Mixed GC
Когда все больше и больше объектов перемещаются в старую область, чтобы избежать нехватки памяти, виртуальная машина запускает смешанный сборщик мусора, а именно смешанный сборщик мусора, который не является старым сборщиком мусора. восстановит не только весь регион Юнд, но и часть старого региона. Здесь следует отметить, что это часть старости, а не вся старость. Вы можете выбрать, какие старые регионы собирать, чтобы контролировать трудоемкую сборку мусора. Также обратите внимание, что смешанный сборщик мусора не является полным сборщиком мусора.
Когда срабатывает MixedGC? Когда параметр -XX: InitialingHeapOccupancyPercent = n определен. Значение по умолчанию - 45%. Этот параметр означает: запускать, когда процентное отношение старости к общему размеру кучи достигает этого порога.
Его этап GC делится на 2 этапа:
1, глобальная метка одновременного доступа
2, копировать живые объекты
Все одновременные маркировки
Глобальная параллельная метка, процесс выполнения делится на пять этапов: начальная метка (начальная метка, STW) отмечает объект, доступный напрямую из корневого узла, на этом этапе будет выполняться GC молодого поколения, Будет глобальная пауза.
G1 GC сканирует ссылки на старое поколение в первоначально отмеченной зоне выживания и отмечает объекты, на которые имеются ссылки. Эта фаза выполняется одновременно с приложением (не-STW), и только после ее завершения может начаться сборка мусора нового поколения STW.
G1 GC ищет доступные (живые) объекты во всей куче. Этот этап выполняется одновременно с приложением и может быть прерван сборкой мусора STW молодого поколения.
Этот этап - восстановление STW, потому что программа запущена, и предыдущая отметка исправлена.
Убрать мусор (Очистка, STW)
Подсчет и сброс статуса флага, этот этап будет STW, этот этап фактически не выполняет сборку мусора, ожидая, пока этап эвакуации будет собран.
Параметры коллектора G1
-XX:+UseG1GC
Используйте сборщик мусора G1 -XX: MaxGCPauseMillis, чтобы установить ожидаемый максимальный индекс времени паузы сборки мусора (JVM сделает все возможное, чтобы достичь этого, но это не гарантируется), значение по умолчанию значение 200 миллисекунд.
-XX:G1HeapRegionSize=n
Размер набора области G1. Значение представляет собой степень двойки, а диапазон - от 1 МБ до 32 МБ. Цель состоит в том, чтобы разделить примерно 2048 регионов на основе наименьшего размера кучи Java. По умолчанию это 1/2000 кучи памяти.
-XX:ParallelGCThreads=n
Установите значение количества рабочих потоков STW. Установите значение n равным количеству логических процессоров. Значение n такое же, как количество логических процессоров, до восьми.
-XX:ConcGCThreads=n
Установите количество потоков для параллельной маркировки. Установите n примерно на 1/4 от числа параллельных потоков сборки мусора (ParallelGCThreads). -XX:InitiatingHeapOccupancyPercent=n
Задайте порог занятости кучи Java, запускающий цикл маркировки. Уровень занятости по умолчанию составляет 45% всей кучи Java.
Рекомендации по оптимизации сборщика мусора G1
Размер молодого поколения
Избегайте использования параметра -Xmn или -XX: NewRatio и других связанных параметров для отображения размера молодого поколения.
Не будь слишком требовательным
Целевая пропускная способность G1 GC - 90% времени приложения и 10% времени сборки мусора.
Чтобы оценить пропускную способность G1 GC, цель паузы не должна быть слишком жесткой. Слишком суровая цель означает, что вы готовы нести больше накладных расходов на сборку мусора, и это напрямую повлияет на пропускную способность.
Читайте также: