Революція 2011 року: Objective-C 3.0, посилання, збирачі сміття

Йосипу Віссаріоновичу, кажуть, термін «гіперпосилання» сподобався б. Це суперечливо, а крім того, ніякого відношення до того, про що ця стаття, не має. Мова в ній піде про зовсім інші посилання. І про інші сутності, які називаються наведеними словами... У 2011 році на зміну системі управління пам'яттю, яку придумав за 20 років до цього великий Бад Тріббл (один з творців першого Mac'a, керівник і автор NeXTSTEP, потім - старший віце-президент Sun Microsystems), прийшла нова.

Старе і нове ще довго співіснували (не знаю, чи доречно тут минулий час), але це був один з тих рідкісних випадків, коли нове було настільки краще і зручніше, що навіть в її початковому і недосконалому вигляді 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. Власне все. Це і є та непрохідна перешкода. Правил і угод було побільше, педантично всі їх дотримати непросто - було потрібно тренування.

Складальник сміття

Про те, як працює збирач пам'яті неважко здогадатися. Він пам'ятає де розташовані всі об'єкти, вважає посилання на них, і якщо об'єкт більше не потрібен, за власним розкладом, запускає процес очищення. Все це відбувається одночасно з роботою програми, забирає у неї ресурси, пам'ять і цикли процесора.

Зате програмісту не треба ні про що піклуватися - наплодив і забув.

Це процес часу виконання, зайве навантаження і все таке - на жаль, в 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'y, йому ніхто не допоможе.

Якщо назва методу починається з одного з чотирьох поєднань букв, після яких головна буква - це метод повертає довгоживучі об'єкти. Інакше - ні.


Чотири магічні поєднання: new, alloc, copy и mutableCopy.

Використання retain, release і autorelease було... заборонено.

Інструментарій для управління пам'яттю був розроблений заново, більш ефективний, і застосовувався він тільки ARC - з нелюдською акуратністю.

Були і мінуси: ARC працював тільки з кодом на Objective-C. Програми для Mac'a і для iOS-пристроїв складаються з фрагментів на C, і звернень до областей пам'яті створених у різних бібліотеках - вони не підтримувалися, для взаємодії з ними потрібні були спеціальні заходи, тобто зайвий час. І це був зайвий привід для помилок.

Розробники ARC доклали масу зусиль для забезпечення сумісності з кодом без підтримки ARC. Майже вийшло - хоча проблеми траплялися.


Проблем, щоправда, виявилося на диво мало - хоч це і була найперша версія технології, що радикально змінювала підвалини.

Продовження слід...

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

COM_SPPAGEBUILDER_NO_ITEMS_FOUND