Революция 2011 года: Objective-C 3.0, ссылки, сборщики мусора

Иосифу Виссарионовичу, говорят, термин “гиперссылка” понравился бы. Это спорно, а кроме того, никакого отношения к тому о чем эта статья, не имеет. Речь в ней пойдет о совсем других ссылках. И о других сущностях называемых приведенными словами… В 2011 году на смену системе управления памятью, которую придумал за 20 лет до этого великий Бад Триббл (один из создателей первого Mac’а, руководитель и автор NeXTSTEP, затем – старший вице-президент Sun Microsystems), пришла новая.

Революция 2011 года: Objective-C 3.0, ссылки, сборщики мусора. Фото.

Старое и новое еще долго сосуществовали (не знаю, уместно ли здесь прошедшее время), но это был один из тех редких случаев, когда новое было настолько лучше и удобнее, что даже в её изначальном и несовершенном виде ARC почти моментально стала основной.

Не все было просто и безоблачно – новая система управления памятью упростила жизнь, но принесла с собой новые проблемы.

ARC был разработан командой LLVM, под управлением Криса Латнера. Одновременно с этим, та же команда, занималась проектом в статусе хобби, тем самым “Objective-C 3.0 без C”, известным сегодня под другим названием. В тот же год компиляторы на основе LLVM 3 окончательно вытеснили GCC из арсенала компании.

Я имел честь общаться с Крисом, примерно в то время – если бы у меня была возможность выбирать главу Apple, я выбрал бы или Скотта Форстолла, или Криса Латнера – а лучше их обоих, и Джонатана Айва им в помощь, для равновесия и внутренней конкуренции…

Это продолжение серии про WWDC 2011, предыдущие части здесь:
Первая часть: WWDC 2011: Apple уходит на облака…;
Вторая часть: WWDC 2011: Про убийство;
Третья часть: iCloud, по другую сторону экрана;
Четвертая часть: Управление памятью и сборщики мусора.

Традиционная система управления памятью

Система Триббла (её так никто не называет, но мы назовем) основана на подсчете числа ссылок на объект.

В первых версиях NeXTSTEP этого не было, что порождало проблемы. Объект, созданный в одном месте программы, мог использоваться в нескольких разных местах – и запросто мог быть удален в одном из этих мест, превратившись в пустышку, попытка обращения к которой неминуемо приводила к аварийному завершению программы.

Вообще не удалять объекты еще хуже: многие из них занимали много места в памяти, а так как и язык, и NeXTSTEP жили динамической и заранее непредсказуемой жизнью (это было одним из их важных преимуществ), подобная практика вела к переполнению памяти, и тому же самому аварийному завершению.

Систему управления памятью основанную на подсчете ссылок изобрел не Бад. Он изобрел то, что в течение почти 20 лет превращало жизнь неофитов в пытку, но в умелых руках было фантастически эффективно – метод autorelease. Только это случилось чуть позже.

В самом начале команд было две, retain (придержать) и release (отпустить). А в объектах появился счетчик ссылок на него. При рождении объекта, его счетчику присваивалось значение 1.

Команда retain добавляла к значению 1, release уменьшала значение на ту же единицу.

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

При обнулении счетчика объект уничтожался. Команда autorelease добавляла в систему динамизм, позволяя создавать временные объекты не заботясь об их уничтожении – они убивались сами (после выхода из контекста).

Как и все прочие, эти объекты рождались с единицей на счетчике, но кроме этого, ссылка на них помещалась в расстрельный список, в NSAutoreleasePool. В каждый оборот цикла управления, программа отправляла всем объектам в списке сообщение release, и очищала его.

Если программист соблюдал правила, в пункт Б прибывали объекты занесенные в Список, если объект был нужен на короткое время (узнать время и вывести его на экран), он тихо и самостоятельно “умирал”. Если на долгое – ему отправлялся retain. Собственно все. Это и есть то непроходимое препятствие. Правил и соглашений было побольше, педантично все их соблюсти непросто – требовалась тренировка.

Сборщик мусора

Революция 2011 года: Objective-C 3.0, ссылки, сборщики мусора. Сборщик мусора. Фото.

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

Зато программисту не надо ни о чем заботиться – наплодил и забыл.

Это процесс времени исполнения, лишняя нагрузка и все такое – увы, в iOS устройствах где это особенно недопустимо, сборщик мусора неуместен. А как же Android, где Java и сборщик мусора “в деле”?

Автоматический подсчет ссылок (ARC)

На пустом месте, с ноля, написать что-то похожее на ARC было бы невозможно, но в группе низкоуровневых (LL!) технологий отделении средств разработки Apple, в рамках проекта по переходу на LLVM-компиляторы, был разработан Xcode Static Analyzer.

Его первые версии мы называли “вредные советы” – он часто ошибался. Но с каждой версией он становился умней, и теперь уже действовало правило: если вы и анализатор расходитесь в мнениях по какому-то поводу, подумайте еще раз: 9 из 10 что он прав. Если не 99 из 100.

ARC делает то же самое, что в течении 20+ лет делали все писавшие программы для NeXT, Apple Cocoa и Apple Cocoa Touch – только с нечеловеческой педантичностью. И во время компиляции, так же как и люди до него, ARC генерирует код для управления памятью.

Управление памяти основано на том же принципе – на подсчете ссылок. ARC похож на магию, но он не магия. Когда человек принимает решение о том, в каком виде отдавать объект во внешний мир (в приговоренном или нет), он опирается на здравый смысл и на знание жизни. У ARC ни первого, ни второго – нет.

Соглашения об отражении долговечности возвращаемых объектов, существовавшие уже полтора десятка лет, стали на порядок более важными, их пришлось уточнить: если мы не поможем ARC’у, ему никто не поможет.

Если название метода начинается с одного из четырех сочетаний букв, после которых заглавная буква – это метод возвращающий долгоживущие объекты. Иначе – нет.

Четыре магических сочетания: new, alloc, copy и mutableCopy.

Использование retain, release и autorelease было… запрещено.

Инструментарий для управления памятью был разработан заново, более эффективный, и применялся он только ARC – с нечеловеческой аккуратностью.

Были и минусы: ARC работал только с кодом на Objective-C. Программы для Mac’а и для iOS-устройств состоят из фрагментов на C, и обращений к областям памяти созданным в разных библиотеках – они не поддерживались, для взаимодействия с ними требовались специальные меры, то есть лишнее время. И это был лишний повод для ошибок.

Разработчики ARC приложили массу усилий для обеспечения совместимости с кодом без поддержки ARC. Почти получилось – хотя проблемы случались.

Проблем, правда, оказалось на удивление мало – хоть это и была самая первая версия технологии, радикально менявшей устои.

Революция 2011 года: Objective-C 3.0, ссылки, сборщики мусора. Автоматический подсчет ссылок (ARC). Фото.

Продолжение следует…

Предлагаем подписаться на наш канал в «Яндекс.Дзен». Там вы сможете найти эксклюзивные материалы, которых нет на сайте.

История AppleРазработка приложений для iOS