Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Эволюция сборщика мусора в Ruby. RGenGC

Anna | 20.06.2014 | нет комментариев

Вопрос продуктивности неизменно был одним из особенно обговариваемых и востребованных в Ruby-сообществе. Будь то высоконагруженный веб-сайт либо примитивный скрипт по бекапу данных — скорость работы является их важнейшей колляцией. При этом познание вероятностей и ограничений языка разработки нередко служит значимым источником идей для оптимизации, разрешает «выжать» максимум из системы.

В статье речь пойдет об одной из особенно крепко влияющих на продуктивность частей языка Ruby — сборщике мусора, алгорифмах его работы и совершенствованиях, внесенных в его работу в последних версиях языка. Речь пойдет о особенно распространенной, «канонической» реализации Ruby — так называемой MRI либо CRuby.

Основы

Сборка мусора (Garbage Collection; GC) в языках программирования — механизм, обеспечивающий механическое управление памятью без вмешательства программиста. GC не является специфической спецификой Ruby — сходственный механизм применяется в существенной части современных языков разработки: Java, Python, C# и других. В MRI применяется типичный Mark-and-Sweep алгорифм сборки мусора, разработанный в дальнем 1960 году.

Ruby использует «кучу» для выделения памяти под новые объекты. Процесс создания объектов прерывается при наступлении одного из 2-х условий: память программы закончилась либо достигнут определенный порог выделения памяти — так называемый malloc_limit. В данный момент MRI запускает сборку мусора, вернее ее первую, «mark» фазу.

image

Сборщик мусора проходит дерево объектов, находящихся в памяти программы, начиная с «корневых» объектов — это всеобщии переменные либо внутренние конструкции языка. Пробегая по ссылкам объектов друг на друга, сборщик мусора помечает объекты как используемые. Все данные, не помеченные как используемые в mark-фазе — «мусор» и память, которую они занимают, может быть освобождена. Освобождение памяти от «мусора» происходит во 2-й, sweep-фазе GC.

Оптимизация сборщика мусора. Ruby 1.9.3 и 2.0

Типичный Mark-and-Sweep алгорифм имеет ряд недостатков. Раньше каждого это существенные паузы в работе программы, на время которых выполнение пригодного пользовательского кода прекращается, а работает сборщик мусора. Чем длиннее такие «stop-the-world» паузы, тем неторопливей работает программа с точки зрения финального пользователя. Для уменьшения продолжительности пауз, затрачиваемых на сборку мусора, в Ruby 1.9.3 был реализован алгорифм Lazy Sweep. Начиная с этой версии MRI sweep-этап сборки мусора не заканчивается полным освобождением памяти от непотребных объектов, а освобождает только то число памяти, которое нужно для продолжения выполнения программы — для создания нового объекта. При создании дальнейшего объекта вновь производится некоторое освобождение памяти и так дальше.

В Ruby 2.0 было интегрировано еще одно совершенствование сборщика мусора — Bitmap Marking GC. Данный алгорифм направлен на Unix системы, в которых при создании дочерних процессов при помощи forkприменяется copy-on-write механизм. Зарожденный процесс создается стремительно, от того что его память является лишь «отображением» памяти соответствующего родительского процесса. Настоящее распределение памяти родительского и дочернего процесса происходит позже записи каких-либо данных в всеобщую область памяти. Многие знаменитые Ruby-библиотеки применяют fork, скажем знаменитый сервер приложений Unicorn и библиотека для выполнения фоновых задач Resque. Впрочем типичный сборщик мусора в MRI нехорошо гармонировал с семантикой fork, от того что во время mark-фазы устанавливал флаг «используемости» у всякого объекта, тем самым модифицируя существенную часть «кучи», реально нивелируя тем самым превосходства copy-on-write механизма для Ruby-процессов. В Ruby 2.0 флаги, применяются ли объекты либо нет, были вынесены в отдельную конструкцию — битовую маску, хранящуюся самостоятельно от самих объектов. Это дозволило гораздо увеличить объем памяти, разделяемый процессами при fork и отменнее применять превосходства copy-on-write семантики.

malloc_limit. Задача 8 МБ.

Важнейшей колляцией сборщика мусора является параметр malloc_limit — порог выделения памяти, позже которого запускается GC. Впрочем значение этой колляции по-умолчанию было весьма небольшим — 8 МБ. В современных системах обработка запроса на веб-сайте может приводить к выборке десятков мегабайт данных из базы либо чтению крупных файлов. При этом сборка мусора производится слишком Зачастую, снижая скорость работы программы.

Отчасти для решения этой задачи разработчиками серверов приложений предпринимались попытки сделать поведение сборщика мусора больше предсказуемым и свести к минимуму воздействие GC на скорость обработки HTTP-запросов. Это привело к происхождению таких спецтехнологий, как Unicorn OobGC иPassenger Out-of-Band Work. Оба решения отключают сборку мусора на время обработки запроса и запускают его принудительно позже того, как запрос обработан сервером. Такой механизм также не лишен недостатков: GC может запускаться Почаще, чем необходимо, если запросы «легковесные», либо, напротив — процесс может «съесть» слишком много памяти.

Функционал malloc_limit был пересмотрен в Ruby 2.1 — порог срабатывания GC стал приспособиться к поведению приложения, а значение по-умолчанию было увеличено до 16 МБ. Сейчас malloc_limitмеханически изменяется при громоздком выделении памяти, в итоге чего сборщик мусора запускается гораздо реже.

image

Ruby 2.1. Поколения объектов

Релиз Ruby 2.1 был ознаменован существенными изменениями в алгорифме работы GC. В язык был интегрирован сборщик мусора на основе поколений. Его работа основана на догадке о том, что множество объектов, создаваемых в программе — «гибнут молодыми». Таким образом, основная действие сборщика мусора связана с объектами, имеющими короткий жизненный цикл.

В Ruby память разбита на 2 поколения объектов — поколение молодых объектов и старшее поколение, к которому относятся объекты, пережившие правда бы одну сборку мусора. В большинстве случаев сборка мусора осуществляется только внутри молодого поколения. Лишь в момент, когда память заканчивается — выполняется полная сборка мусора с участием обоих поколений.

Главной задачей при таком подходе становятся обратные ссылки с объектов старшего поколения на объекты молодого поколения.

image

Если не рассматривать вероятность происхождения таких ссылок, minor GC — сборка мусора внутри младшего поколения может пометить как мусор реально надобные, применяющиеся объекты. Для решения этой задачи применяется особая конструкция — Remember Set, в которой запоминаются проблемные ссылки. Для определения факта возникновения таких ссылок применяется барьер на чтение в Ruby-интерпретаторе. «Взрослые» объекты, с которых имеются ссылки на объекты младшего поколения применяются как корневые при minor-сборке мусора.

Существенным лимитацией сборки мусора в MRI является надобность сохранения обратной совместимости со всеми многочисленными C-растяжениями, разработанными для языка. Именно следственно алгорифм GC в Ruby носит наименование RGenGC — Restricted Generational GC. «Сжатость» сборки мусора заключается в том, что все объекты делятся на 2 типа: shady-объекты — это объекты, которые применяются либо допустимо могут быть использованы в C-растяжениях. Соответственно сборщик мусора не может безвредно перемещать их между поколениями. Если такой объект попадет в старшее поколение, он не будет защищен барьером на чтение, от того что бывшая семантика языка не требовала от C-растяжений применения таких барьеров. В итоге могут появиться «проблемные» ссылки, описанные выше.

Shady-объекты не участвуют в поколениях сборки мусора, между поколениями мигрируют только обыкновенные объекты. Такое решение дозволило сберечь совместимость с существующими C-библиотеками и упростило разработку сборщика мусора. Впрочем, в свою очередь, оно исключает из работы нового сборщика мусора существенное число объектов. Тем не менее, по измерениям разработчиков RGenGC, убыстрение работы приложений при применении нового сборщика мусора составляет порядка 10%.

Планы на грядущее

Сборщик мусора — одна из особенно динамично прогрессирующих частей языка. В ближайших планах — доведение числа поколений языка до 3. Из больше глобальных пророческой планируется вступление параллелизма в mark и sweep фазы сборки мусора, что дозволит отменнее применять вероятности современных многоядерных процессоров.

Добавочные источники информации

Презентация Коити Сасада на RubyConf 2013
Книга Ruby Under a Microscope (2013)

Источник: programmingmaster.ru
Оставить комментарий
БАЗА ЗНАНИЙ
СЛУЧАЙНАЯ СТАТЬЯ
СЛУЧАЙНЫЙ БЛОГ
СЛУЧАЙНЫЙ МОД
СЛУЧАЙНЫЙ СКИН
НОВЫЕ МОДЫ
НОВЫЕ СКИНЫ
НАКОПЛЕННЫЙ ОПЫТ
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB