Dmitriy Azarov

Сравнение ARC и Garbage Collector

С приходом ARC (в XCode 4.2) разработчики iOS и OS X получили возможность не вызывать вручную retain release в Objective C. Такой подход стал очень похож на работу сборщика мусора. (нет). ARC является подвидом сборщика мусора, но для простоты понимания тут будем считать что это разные системы и ARC подразумевается использование со Swift, а сборщик мусора из мира .NET. Сравнение начнем с принципов работы каждого механизма.

Если не очищать использованные переменные то очень скоро вся доступная память кончится. Поэтому каждый объект живет какую-то свою жизнь. Как у веб страниц есть Life Cycle, у контроллеров свой жизненный цикл так и у объектов в памяти есть свой жизненный цикл. На мобильных устройствах это особо важно, так как проблемы с утечкой или малой памятью довольно частое явление.

До изобретения модных ARC и GC приходилось вручную управлять жизненным циклом объектов. Для этого существовали такие операторы как malloc, free, retain, release. Цель обеих систем GC и ARC оградить разработчика от ручного управления памятью. Оба подхода похожи по использованию в своих языках программирования (разработчику не требуется ничего дополнительно писать), однако знать как они работаю очень важно.

Как считать объект живым

При инициализации объекта происходит выделение участка памяти в куче и сохранение ссылки на этот участок памяти в стеке. Какие есть варианты автоматического управления временем жизни объекта?

  • Подсчет ссылок самый очевидный вариант считать количество указателей на объект, и в случае, если их количество равно нулю уничтожать объект.

Сборщик мусора (Garbage Collector)

Garbage Collector (GC) это техника, которая используется для управления памятью в платформах, где есть среда выполнения (.NET и Java). GC работает в рантайме CLR (Common Language Runtime). Механизм работает в фоне в самой среде исполнения и обнаруживает неиспользуемые объекты.

Сборщик живет своей жизнью. Он начинает работу в недетерминированные интервалы времени. Инициировать его работу может множество факторов, например прошло некоторое количество времени, или CLR заметила, что кончается память. И в этот момент среда исполнения и сборщик мусора принимают решение, что пора освободить неиспользуемые объекты из памяти.

Сборщик мусора работает с принципом "Всегда безопаснее не очищать", это означает, что если сборщик сомневается в необходимости объекта он оставит его живым. Также при работает сборщик мусора после очистки поколений сжимает используемую память. Если при работе с приложением требуется большое количество создания объектов и их освобождения то тут GC проседает по времени, которое требуется для осознания, что объекты больше не нужны и запуску ручной сборки мусора.

В некоторых случаях требуется провести очистку ресурсов (открытых файлов или других ресурсов) по удалению объекта из памяти. Так как разработчик не может предсказать, когда объект будет удален из памяти, введены понятия IDisposable и Finalizer. Шаблон Disposable позволяет типу реализовать специальные вызовы, которые будут вызваны перед освобождением объекта.

Плюсы

  • Может очищать целые графы объектов, включая циклические ссылки
  • Работает в фоне независимо от работы приложения

Минусы

  • Из-за того, что GC работает в фоне нельзя точно сказать, когда объекты будут освобождены из памяти
  • Из-за особенностей работы сборщика мусора, на время сборки он приостанавливает работу приложения. Правда все это сильно контролируется сборщиком, чтобы он не сильно вмешивался в общую производительность приложения, данный факт есть.
  • Работа происходит в рантайме, в фоне, что дополнительно занимает как процессорное время так и дополнительную память на работу сборщика.

Automatic Reference Counting (ARC)

С другой стороны управляемого кода живет ARC. Это полностью часть кода. Нет фоновых процессов управления памяти и освобождение памяти полностью детерменировано, означает, что можно точно предсказать, когда он произойдет. Основной затык при работе с ARC это циклические ссылки, как только объекты ссылаются друг на друга разработчик обязан либо вручную обнулить ссылку на объект, либо указать какую ссылку не считать при работе ARC.

Пример циклической ссылки

По умолчанию ARC считает все ссылки сильными. Две сильные ссылки друг на другая делают невозможные освобождение памяти ARC'ом. Для этого ввели модификаторы ссылок. Так объект может быть помечен weak, в таком случае ARC не будет инкрементировать счетчик ссылок для этого объекта. В хорошем дизайне отношения родитель / потомок - родитель хранит сильную ссылку на потомка, а потомок хранит слабую ссылку на родителя.

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

Плюсы

  • Предсказуемое поведение
  • Объекты уничтожаются сразу, как только они больше не нужны
  • Вся работа происходит в момент компиляции, издержки на рантайм минимальны (но все же они есть, т. к. считает ссылки ARC в рантайме)

Минусы

  • Не работает с циклическими ссылками без участия со стороны разработчика
  • 10 май 2017
  • arc, garbage collector
3 комментария
Федот, 18 мая 2017 г.
А как дела с кастомными аллокаторами? Что с фрагментацией?
ответить
Петручио, 18 мая 2017 г.
Двухмерные массивы то уже поддерживаются со строками???
ответить
Kek, 18 июня 2017 г.
ARC не уничтожит объект "сразу как только не нужен". Есть еще autoreleasepool-ы, о которых стоит думать при работе с большим к-вом объектов.
ответить
Ваш комментарий
адрес не будет опубликован
Текст