Память и производительность
Swift управляет памятью объектов через ARC — Automatic Reference Counting: компилятор вставляет вызовы retain/release на этапе компиляции, считает владельцев каждого объекта и освобождает его в тот миг, когда счётчик достигает нуля. Это не трассирующий сборщик мусора — фонового сканирования и непредсказуемых пауз нет, поэтому deinit вызывается детерминированно. Понимание одного этого различия отделяет инженера, который уверенно ищет утечку, от того, кто повторяет мифы про «сборщик Swift, работающий под нехваткой памяти».
Тема делится на две половины. Сначала модель памяти: как ARC считает владельцев, что означают strong, weak и unowned, как возникает цикл удержания, когда два объекта — или замыкание и его self — держат друг друга сильными ссылками, и как список захвата его разрывает. Затем производительность: почему значимая семантика вместе с copy-on-write делают копирование struct дешёвым, где ссылочные типы тратят кучу и трафик ARC, когда диспетчеризация динамическая, а когда статическая, и как профилировать реальную работу через Instruments вместо догадок.
Карта темы
- Память и ARC — подсчёт ссылок на этапе компиляции,
strong/weak/unowned, циклы удержания из взаимных ссылок и захваченногоself, разрыв через[weak self], момент вызоваdeinitи почему значимым типам ARC не нужен. - Производительность — значимая семантика и copy-on-write, стек против кучи и цена ссылочных типов, статическая против динамической диспетчеризации, измерение через Time Profiler / Allocations / Leaks и ловушки главного потока, роняющие кадры.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
| Думать, что ARC сканирует кучу, как сборщик мусора | Неверная модель того, когда и как освобождаются объекты |
Менять местами weak и unowned — считать, что падает weak | Чтение unowned после освобождения — это UB |
| Ждать, что ARC сам обнаружит и разорвёт цикл удержания | Два объекта с сильными ссылками друг на друга утекают навсегда |
| Считать struct всегда дешёвым в копировании и на стеке | Захваченный или упакованный struct — в куче; большие struct стоят дорого |
| Гадать о hot path вместо профилирования | Оптимизируется код, который никогда не был узким местом |
| Декодировать картинки или парсить JSON на главном потоке | Бюджет кадра превышен, скролл роняет кадры |
Значение для собеседований
Память и производительность спрашивают, чтобы проверить, понимаете ли вы машину или пересказываете рекламу. Кандидат, который говорит «ARC вставляет retain/release на этапе компиляции и освобождает при нуле, поэтому освобождение детерминировано», сразу опережает того, кто зовёт это «сборщиком мусора Swift».
Что обычно проверяют:
- Что такое ARC и чем он отличается от трассирующего сборщика.
- Разницу между
weak(optional, обнуляется) иunowned(non-optional, падает после освобождения). - Как возникает цикл удержания — взаимные ссылки или замыкание, захватившее
self, — и как его разорвать. - Почему значимые типы дёшевы под copy-on-write и где ссылочные тратят кучу и ARC.
- Как доказать утечку или зависание через Instruments, а не догадкой.
Типичный неверный ответ: «В Swift есть сборщик мусора, который освобождает объекты при нехватке памяти». На деле ARC — это подсчёт ссылок на этапе компиляции с детерминированным освобождением без пауз, полная противоположность недетерминированности, которую даёт сборщик.