Санкт-Петербургская группа тестирования JVM


« Hotspot FAQ | Main | Sun TechDays в Питер... »
20070311 воскресенье Март 11, 2007

Основы сборки мусора в Hotspot JVM

Сборка мусора в языке Java является предметом постоянных обсуждений и всевозможных заблуждений. В этом посте мы постараемся пролить свет на некоторые аспекты работы сборщика мусора в виртуальной машине Hotspot JVM.

Спецификация виртуальной машины не содержит каких-либо требований к механизму управления памятью (кроме того, что «память очищается автоматически с помощью механизма сборки мусора»), поэтому при реализации сборщика мусора разработчики ничем не ограничены. JDK 6 предоставляет 3 сборщика мусора: последовательный SerialGC, параллельный ParallelGC, совместный ConcMarkSweepGC.

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

На текущий момент все сборщики мусора в виртуальной машине Sun Hotspot JVM относятся к типу сборщиков мусора, основанных на поколениях (generational garbage collectors). Сборщики такого типа используют наблюдение, справедливое для Java и ряда других языков программирования: большая часть объектов, создаваемых при работе приложения, становится мусором в течение очень небольшого промежутка времени («most objects die young»). При использовании таких сборщиков вся память делится на области, называемые поколениями. В HotSpot есть два основных поколения: область Young generation, в которой размещаются только что созданные объекты, и Old (или Tenured) generation, в которую перемещаются объекты, пережившие несколько сборок мусора. Young generation, как правило, меньше по размерам чем Old generation, оно заполняется быстрее, и сборки мусора в нём проводятся часто. Сборки мусора в Young generation занимают мало времени и являются очень эффективными, так как большинство объектов, содержащихся в этой области, являются мусором. Old generation имеет больший размер и заполняется медленнее. Сборки мусора в ней проводятся реже и времени они могут отнимать значительно больше.

Главное приемущество разделения памяти на поколения в том, что для сборки мусора в различных поколениях могут применяться различные алгоритмы. Для частых сборок в небольшом по размеру Young generation, содержащем большое число ненужных объектов, могут использоваться копирующие алгоритмы, ориентированные в первую очередь на скорость, в то время как алгоритм очистки Old generation должен учитывать ее большой объем (стоит отметить, что в Hotspot JVM, помимо областей Young generation и Old generation есть область памяти, называемая Permanent generation. В ней виртуальная машина хранит различную информацию, относящуюся к загруженным классам, откомпилированные методы, строки после String.intern(). При этом объекты из Permanent generation также могут быть удалены сборщиком мусора.

В этом посте мы остановимся на работе последовательного сборщика мусора—SerialGC. Этот сборщик мусора используется виртуальной машиной по умолчанию на так называемых машинах клиентского типа (в отличии от машин серверного типа, они имеют меньше двух процессоров и меньше двух гигабайт оперативной памяти). Можно явно указать, что следует использовать именно этот сборщик мусора, при помощи флага -XX:+UseSerialGC. Последовательный сборщик мусора использует модель работы, называемую stop-the-world. То есть на время его работы все потоки приложения приостанавливаются. Название "последовательный" означает, что этот сборщик мусора использует последовательный (не параллельный) алгоритм: вне зависимости от числа доступных процессоров, сборка мусора выполняется только одним потоком.

Рассмотрим процесс сборки мусора SerialGC более детально.

Область памяти Young generation состоит из трёх областей: Eden и двух меньших по размеру survivor spaces. Большинство объектов создаются в области Eden, за исключением очень больших объектов, которые не могут быть размещены в ней и поэтому сразу размещаются в Old generation. В survivor spaces перемещаются объекты, которые пережили по крайней мере одну сборку мусора, но ещё не достигли порога 'старости' (tenuring threshold), чтобы быть перемещенными в Old generation.

Когда Young generation заполняется, то в этой области запускается процесс лёгкой сборки (minor collection, в отличие от процесса сборки, проводимого над всей heap памятью—full collection). Он происходит следующим образом: в начале работы одно из survivor spaces, To space, является пустым, а другое, From space, содержит объекты, пережившие предыдущие сборки. Сборщик мусора ищет живые объекты в Eden и копирует их в To space, а затем копирует туда же и живые "молодые" (то есть не пережившие еще заданное число сборок мусора, tenuring threshold) объекты из From space. Старые объекты из From space перемещаются в Old generation. После лёгкой сборки From space и To space меняются ролями, область Eden становится пустой, а число объектов в Old generation увеличивается.

Легкая сборкаЛегкая сборка завершена

Если в процессе копирования живых объектов To space переполняется, то оставшиеся живые объекты из Eden и From space, которым не хватило места в To space, будут перемещены в Old generation, независимо от того, сколько сборок мусора они пережили.

Поскольку при использовании этого алгоритма сборщик мусора просто копирует все живые объекты из одной области памяти в другую, то такой сборщик мусора называется копирующим. Очевидно, что для работы копирующего сборщика мусора у приложения всегда должна быть свободная область памяти, в которую будут копироваться живые объекты, и такой алгоритм может применяться для областей памяти сравнительно небольших по отношению к общему размеру памяти приложения. Young generation как раз удовлетворяет этому условию (по умолчанию на машинах клиентского типа эта область занимает около 10% кучи (значение может варьироваться в зависимости от платформы).

 Однако, для сборки мусора в Old gen, занимающем больщую часть всей памяти, используется другой алгоритм.

В Old generation сборка мусора происходит с использованием алгоритма Mark-Sweep-Compact, который состоит из трёх фаз. В фазе Mark (пометка) сборщик мусора помечает все живые объекты, затем, в фазе Sweep (освобождение) все непомеченные объекты удаляются, а в фазе Сompact (уплотнение) все живые объекты перемещаются в начало Old generation, в результате чего свободная память после очистки представляет собой непрерывную область. Фаза уплотнения выполняется для того, чтобы избежать фрагментации и упростить процесс выделения памяти в Old generation.

Когда свободная память представляет собой непрерывную область, то для выделения памяти под создаваемый объект можно использовать очень быстрый (около десятка машинных инструкций) алгоритм bump-the-pointer: адрес начала свободной памяти хранится в специальном указателе, и когда поступает запрос на создание нового объекта, код проверяет, что для нового объекта достаточно места, и, если это так, то просто увеличивает указатель на размер объекта.

Очистка Old GenerationУплотнение Old Generation

Последовательный сборщик мусора отлично подходит для большинства приложений, использующих до 200 мегабайт кучи, работающих на машинах клиентского типа и не предъявляющих жёстких требований к величине пауз, затрачиваемых на сборку мусора. В то же время модель stop-the-world может вызвать длительные паузы в работе приложения при использовании больших объёмов памяти. Кроме того, последовательный алгоритм работы не позволяет оптимально использовать вычислительные ресурсы компьютера, и последовательный сборщик мусора может стать узким местом при работе приложения на многопроцесcорных машинах.

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

Ссылки:
Java HotSpot Garbage Collection
Memory Management in the Java HotSpot™ Virtual Machine
Frequently Asked Questions about Garbage Collection in the HotspotTM JavaTM Virtual Machine

Семен Бойков 

опубликовал vmrobot ( мар 11 2007, 05:16:49 PM MSK ) Permalink Комментарии [4]

Trackback URL: http://blogs.sun.com/vmrobot/entry/%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D1%8B_%D1%81%D0%B1%D0%BE%D1%80%D0%BA%D0%B8_%D0%BC%D1%83%D1%81%D0%BE%D1%80%D0%B0_%D0%B2_hotspot
Комментарии:

Если я правильно понял, то CMS в JDK6 делает Compaction. Так? А в JDK1.4 и 1.5 CMS делает Compaction?

опубликовал Igor Malinovski Март 28, 2007 at 12:27 PM MSD #

"В тоже время" -> "В то же время"

опубликовал somebody Июнь 03, 2007 at 07:36 PM MSD #

Спасибо!

опубликовал Kirill Июнь 04, 2007 at 05:10 PM MSD #

А про параллельный GC будет статья? Интересно узнать, как он работает.

опубликовал WFrag Декабрь 14, 2007 at 12:32 PM MSK #

Опубликовать комментарий:

Имя
E-Mail:
URL:

Ваш комментарий:

HTML Syntax: Отключен

Хиты страниц за сегодня: 98