Добавочного сбора мусора в Ruby 2.2

Добавочного сбора мусора в Ruby 2.2

460

В данной статье рассматриваются инкрементального сборщика мусора (incremental GC ), которая была введена в Ruby 2.2. RincGC дозволяет достигнуть наиболее недлинные паузы (паузы GC времени) по сопоставлению с Ruby 2.1. Мы называем этот метод RincGC.
Он писал YARV, сборщик мусора поколений (RgenGC) для Ruby 2.1, а также incremental GC в ruby 2.2 и в данной статье. О создателе: Коичи Sasada (Коичи Sasada) работает на Heroku с Нобу и Мэтт съесть за ядро ruby.

M&S является одним из самых обычных алгоритмов сборки мусора, которая состоит из 2-ух шагов:
1. Предпосылкой
Ruby употребляет GC для автоматического сбора неиспользуемых объектов. Развертки: утилизируйте все неименованные объекты, так как они больше не употребляются Марка: пройти через все живые объекты и отметьте их в качестве «живого объекта»
2. 1-ая версия Ruby уже употреблял mark and sweep (M&S) — метода. Благодаря garbage collector ruby программеры не должны удалить их вручную, и не придется волноваться о ошибках с сиим снять.
M&S-это познание того, что все отысканные предметы из числа живых объектов являются настоящими объектами. M&S метода чрезвычайно проста, и она работает чрезвычайно отлично.

Mark & sweep GC метод
Но, так как этот метод тяжело применить moving GC методы, такие как уплотнения(уплотнения) и копирование(тиражирование). Это обычный и действенный метод (и консервативные мусора) дозволяет писать расширения в C достаточно просто. В Ruby есть много нужных расширений.
Но в начале, наличие огромного количества расширений и предоставляя множество функций с помощью расширений было огромное преимущество, как это сделал интерпретатор Ruby и наиболее популярным. На данный момент пишу C расширениями не так принципиально, поэтому что мы можем применять FFI (foreign function interface).
GC замедляет работу программы на языке Ruby из-за накладных расходов на вывоз мусора. Каждый мусора приостанавливает работу приложения. Более принципиальные потенциальные трудности производительности(пропускной возможности) и пауз(паузы). Иными словами, низкая производительность GC наращивает Общее время выполнения вашего приложения. Долгой паузы влияют UI/UX web-приложений. Хотя M&S метод прост и непревзойденно работает, есть несколько заморочек.
Вновь сделанные объекты находятся в «юный космос» и, соответственно, обозначены как «юные » объекты». Мы знаем, что в объектно-направленном программировании объекты погибают юными. Раз места в юных места для сотворения объектов, не довольно, потом запускает сборщик мусора для «старенького места». Опосля того, как юный объектов переживет несколько garbage collection (3 в Ruby 2.2), они перебегают в разряд «старенькых» и будет размещен в «древнем пространстве». Мы называем «Minor GC» когда сборщик мусора в юном пространстве, и главные GC» для всех, и для юных и для старенькых пространств. Generational GC разделяет место в куче (heap space) на несколько частей в течение пары поколений (в Ruby мы разделяем место кучи: юные и старенькые, место). Мы реализовали generational GC метод с некими переменами и именуется наш метод и реализация сборки мусора «RGenGC». Вы сможете выяснить подробности-смотрите мою презентацию и слайды на EuRuKo. Чтоб решить трудности производительности в Ruby 2.1 представлены сборщик мусора на основании поколений (generational GC). Потому мы должны запустить сбор мусора-это лишь для юных места».
RGenGC существенно увеличивает эффективность сбора мусора из-за чрезвычайно скорого Minor GC. Стоит отметить, что главные GC приостанавливает выполнение программы в течение долгого времени и это время, равное продолжительности паузы в Ruby 2.0 и наиболее ранешних версий. Большая часть сборщик мусора выполняет Minor GC.

Пауза в больших GC и Minor GC
Чтоб решить делему с долгой паузой, лучше подступает инкрементального сборщика мусора.
Это дозволяет получить наиболее стабильную работу. Заместо долгой паузы, инкрементальный сборщик мусора вопросцев много маленьких перерывов. Incremental garbage collection
Метод incremental garbage collection разделяет процесс сборки на наиболее маленькие процессы и их заместители GC действий и действий Ruby. Общественная длительность пауз остается той же (либо чуток больше, из-за накладных расходов при использовании инкрементального сборщика мусора), но каждый перерыв будет короче.
Ленивый развертки уменьшает Длительность пауз и наполовину incremental GC метод. Сейчас нам необходимо сделать шаг работы главных incremental GC. Смысл бездельничать пуска развертки свип-фазы не сходу, но равномерно. В Ruby 1.9.3 возникли «ленивые sweep GC, который уменьшает Продолжительность пауз в фазе зачистки.
Введем три понятия, чтоб разъяснить процесс добавочные нотки энтузиазм: белоснежный объект(белоснежный объект) — непомеченные объекты, «сероватый объект(сероватый объект) помечен, но может ссылаться на белоснежные объекты, «темный объект»(темный объекта) — помечено, но не указывают, хоть какой белоснежный объект.
4. Изменение цвета начального объекта до темного. Повторяйте, пока не сероватые объекты, и будет лишь темный и белоснежный. С помощью этих 3-х цветов мы можем разъяснить «mark and sweep» метод:
1. Выбрать хоть какой сероватый объект и выберите объект, к которому оно относится также сероватый. 3. Очевидно «живые» объекты, такие как объекты в стеке будут помечены сероватым цветом. Собирать белоснежные объекты, как и все живые объекты покрашены в темный. Все имеющиеся объекты помечаются как белоснежный
2.
Чтоб сделать весь процесс пошагового, нужно сделать шаг (3) добавочные. План: выбрать какую-то сероватую объектов, а также Марк Грэй объекты, к которым они относятся, а потом переключиться на выполнение кода на Ruby, а потом возвратиться к процессу тегов и др.

Обычные знаки (STW: приостановить мир) в сопоставлении с добавочной
Когда поэтапного процесса, отмечает (incremental маркировки объектов есть одна неувязка. Для предотвращения в этом случае мы используем «барьер записи» (write-барьер), чтоб найти создание таковых ссылок темное на белоснежном. Это неувязка, поэтому что темный объект, по определению, не может ссылаться на белоснежные объекты. Темные объекты могут указывать белки в процессе выполнения кода на Ruby.
Собирая все «живые» объекты » — это ошибка, и его следует избегать. ary << obj
# опосля сотворения obj GC не запускается

Сейчас темный объект ссылается на белоснежный объект. К примеру, массив ‘ary’ is marked as темный. ary = []
# GC запускается и темные метки

Объект ‘obj = Object.новейший’ будет белоснежный раз запустить этот код. Раз нет сероватого объекты, ссылающиеся ‘obj’, ‘obj’ будет белоснежный в конце фазы маркировки объектов и соответственно утилизировать в ошибки.
Когда это происходит, темный объект меняет собственный цвет на сероватый (либо сероватый с указателем белоснежный объект). Барьеры входа на сто процентов решить делему сбора всех живых объектов. Запись барьер обнаруживает, когда была изготовлена ссылка с темного объекта на белоснежном. Барьер записи вызывается каждый раз, когда объект начинает ссылаться на новейший объект.
У вас может быть вопросец: «почему Руби все еще не употребляют этот обычный метод GC?» Как вы сможете созидать, это не так уж и трудно. Это основное значение инкрементного метода.
Добавочного сбора мусора в Ruby 2.2
При реализации поэтапного процесса, отмечает в интерпретатор Ruby (CRuby) существует суровая неувязка — отсутствие барьеров для входа на рынок.
Generational GC, который был реализован в Ruby 2.1, также нужно и барьеры для входа. С введением концепции незащищенный объект (незащищенного объекта), можно воплотить generational GC в Ruby 2.1 Для реализации generational GC, мы разработали новейший способ — «барьер записи неохраняемых объектов» (написать барьер незащищенные объекты). Мы не можем контролировать ссылки из незащищенных объектов. Это значит, что мы разделили все объекты на защищенные и незащищенные. Таковым образом, мы можем гарантировать, что все ссылки охраняемые объекты находятся под контролем.
Нарисую все, разумеется, «живые» объекты, в сероватом, в том числе объекты в стеке
3. Поменять собственный цвет на темный. Нарисую все имеющиеся объекты в белоснежный
2. Повторять до тех пор, пока не сероватые объекты. 4. Этот шаг выполняется в несколько шагов. Взять один сероватый объект и выкрасить в сероватый все объекты, на которые она ссылается. Лишь темный и белоснежный. Собирать белоснежные объекты, поэтому что все живые объекты имеют темный цвет Мы также можем верно воплотить incremental GC, используя незащищенные объекты:
1.
Потому мы можем гарантировать, что у нас нет белоснежных живых объектов.

Повторный Просмотр записи барьер незащищенные объекты(WB УНП.) в конце процесса, отмечает.
Большая часть объектов в Ruby это String, Array, Hash, либо обычный(незапятнанный) объектов, сделанных программером. Но, Общее время простоя, связанное с рядом барьеров записи живого незащищенные объекты. Они являются охраняемыми объектами. К огорчению, 4-й шаг может сделать долгая пауза, которая, как мы надеемся избежать. На практике, пауза для записи барьер незащищенные объекты не делают никаких заморочек в большинстве случаев.
Наибольшая Длительность паузы в нашем incremental GC наименее minor GC. Мы сделали постепенный процесс маркировки лишь для больших GC, поэтому что никто не жалуется, пауза в minor GC. Раз вас устраивает время паузы в minor GC, для вас не необходимо волноваться о времени паузы в больших GC.
Потому сборщик мусора работали быстро, мы сделали «незащищенного» точечный набросок, который является незащищенные объекты, и отдельные «помечено» растровое изображение, которое указывает, какие объекты были помечены. Используя логические продукта можно отыскать «темный и незащищенных объектов. Я также употреблял трюк, чтоб воплотить incremental GC в Ruby. У нас есть набор темный и незащищенных объектов.
gc_tracer показывает каждый параметр в файле. Оценка продолжительности пауз incremental GC
Для того, чтоб измерить Продолжительность пауз в процессе сборки мусора, мы будем применять gc_tracer. В gc_tracer есть модуль GC:Tracer, которая дозволяет контролировать характеристики процесса сборки мусора.
Мусора включает в себя последующие мероприятия:
начать
end_mark
end_sweep
newobj
freeobj
введите
выход
Как я обрисовал выше, GC в Ruby имеет две фазы: «mark and sweep». Разумеется, «end_sweep» обозначает конец развертки фазы, и также значит завершения процесса сборки мусора. Событие end_mark» также значит начало развертки фазы. Событие «старт» показывает на начало знака фазы, и «end_mark» — его завершение.
«newobj» и «freeobj» являются случаи, когда выделение памяти для объекта и его релиз.
«введите» значит «ввод GC, связанных с событием». Мы используем «enter» и «exit» действия измерить Продолжительность пауз. И, в конце концов, «выход» значит «exitting GC, связанных с событием» Incremental GC (incremental маркировки и ленивый подметание) употребляет паузы Марк фазы и развертки фазы.
На последующем рисунке показано распределение событий во времени в текущем incremental GC.

Мы можем измерить Текущее время ( в Linux Текущее время является результатом вызова gettimeofday()) для каждого действия. Таковым образом, мы можем измерить Продолжительность пауз в GC с помощью действия «вход» и «выход».
Я использую ko1-test-приложение для сопоставления производительности. ko1-test-app-обычный Rails приложения, написанные для меня, Аарон Паттерсон (Aaron Patterson).
Значение «30000» значит, что мы будем моделировать 30000 запросов. Применять варенье gc_tracer, я добавил грабли правило «test_gc_tracer»:
diff —git a/perf.рейка б/perf.грабли
индекс f336e33..7f4f1bd 100644
— а/perf.грабли
+++ б/perf.грабли
@@ -54,7 +54,7 @@ def app do_test_task
тела.закрыть
конец

-задачка :сделать тест
+def test_run
app = Ko1TestApp::Application.экземпляр
app.приложение

@@ -67,6 +67,22 @@ задачку :сделать тест
}
конец

+задачка :сделать тест
+ test_run
+конец
+
+задачка :сделать test_gc_tracer
+ require ‘gc_tracer’
+ require ‘pp’
+ pp GC.stat
+ file = «лог.#{Процесс.pid}»
+ GC::Tracer.start_logging(файл, действия: %i(enter, exit), gc_stat: false) do
+ test_run
+ конец
+ pp GC.stat
+ ставит «GC-tracer журнальчика: #{file}»
+конец
+
задачка :один раз сделать
app = Ko1TestApp::Application.экземпляр
app.приложение

И побежал bundle exec rake test_gc_tracer KO1TEST_CNT=30000. Результаты будут записаны в файл «лог.xxxx», где xxxx-идентификатор процесса приложения. Файл должен vikladati что-то вроде этого:
У меня есть файл 1,142,907 линий. типа галочку major_by gc_by have_finalizer immediate_sweep гос
введите 1419489706840147 0 newobj 0 0 классным
выход 1419489706840157 0 newobj 0 0 классным
введите 1419489706840184 0 newobj 0 0 классным
выход 1419489706840195 0 newobj 0 0 классным
введите 1419489706840306 0 newobj 0 0 классным
выход 1419489706840313 0 newobj 0 0 классным
введите 1419489706840612 0 newobj 0 0 классным

Мы лицезреем, Продолжительность паузы, используя эту информацию. Столбец «Тип» содержит имя действия, для «галочки» — Текущее время (итог gettimeofday(), количество микросекунд, прошедших с начала эры). Используя 1-ые две строки выше, мы можем измерить Продолжительность паузы: 10 МКС (1419489706840157 — 1419489706840147).
Последующий маленький скрипт, который указывает Длительность каждой паузы. enter_tick = 0
open(ARGV.shift){|f|
f.each_line{|line|
e, тик, * = строчка.split(/s/)
case e
когда ‘enter’
enter_tick = клеща.to_i
когда «выход»
st = клеща.to_i — enter_tick
ставит st, раз st > 100 # наиболее 100 МКС
еще
# помещает строчку
конец
}
}

Лог-файл будет иметь много строк, поэтому что этот скрипт выводит Продолжительность пауз каждые 100 МКС.
На последующем рисунке показан итог измерения.

Это обязана быть пауза, вызванный началом главных GC. Наибольшее время паузы около 15мс(15Kμs). Неповторимые. Но, incremental GC понижает наивысшую задержку до 2 мс (2Kμs). Мы лицезреем, что generational GC имеет 7 больших пауз.
Вывод
Ruby 2.2 употребляется инкрементный метод сборки мусора, чтоб уменьшить время паузы сбора мусора.
Это не влияет на время отклика, раз запрос очень долго, и обстоятельств несколько раз большие GC. Общее время сборки «мусора» не будет сокращено из-за incremental GC. habrahabr.ru Обратите внимание, что incremental GC-это не «серебряная пуля». Как я уже описывал, incremental GC не влияет на производительность.