Как найти утечку памяти в iOS-приложении без использования Memory Graph Debugger?

Ответ

Основные инструменты — Instruments (Allocations и Leaks) и ручная проверка retain cycles.

1. Инструмент Allocations

Запуск: Product > Profile > Allocations в Xcode.

  • Фильтруйте по именам своих классов.
  • Наблюдайте за ростом счетчика #Persistent или #All.
  • Ищите объекты, которые не освобождаются после ожидаемых событий (например, после dismiss контроллера).
  • Используйте Mark Generation (кнопка внизу) для создания контрольных точек и отслеживания объектов, созданных между ними.

2. Инструмент Leaks

Запуск: Product > Profile > Leaks.

  • Прямо показывает утечки — объекты, на которые больше нет сильных ссылок, но память не освобождена.
  • Часто указывает на проблемы с C-кодом (Core Foundation, необработанные указатели).

3. Ручная проверка retain cycles

  • Проверка вызова deinit:
    class MyViewController: UIViewController {
        deinit {
            print("MyViewController deallocated") // Если не печатается — есть цикл
        }
    }
  • Типичные источники циклов:
    • Замыкания: Всегда используйте [weak self] или [unowned self], когда self удерживает замыкание.
    • Делегаты: Должны быть объявлены как weak.
    • Таймеры: Timer сильно ссылается на target. Используйте блоки или инвалидируйте в deinit.
    • Уведомления (NotificationCenter): Не забывайте удалять наблюдателей.
  • Косвенный анализ: Используйте Debug Memory Graph (кнопка в Xcode) для визуализации графа объектов в конкретный момент времени и поиска неожиданных сильных ссылок.

Ответ 18+ 🔞

А, ну так, слушай, смотри, вот ты тут сидишь и думаешь: «Блядь, куда память девается, как будто её кто-то жрёт?» Это, сука, классика. Ну ладно, не паникуй, сейчас разберёмся, как эту хитрую жопу поймать.

Вот тебе основные штуки, которые надо в глаза тыкать.

1. Инструмент Allocations — наш главный подследственный

Запускаешь: Product > Profile > Allocations в Xcode, и понеслась.

  • Там сверху есть фильтр — вбиваешь туда имена своих классов, как будто ищешь иголку в стоге говна.
  • Смотришь на колонки #Persistent или #All. Если число растёт, а должно падать — это, блядь, подозрительно. Например, закрыл контроллер, а он в памяти как будто прирос намертво.
  • Есть там кнопочка Mark Generation внизу — это вообще огонь. Нажал в начале сценария (например, открыл экран), потом что-то сделал и закрыл, нажал ещё раз. И смотришь, какие новые объекты между этими «поколениями» застряли. Вот они, твои паразиты!

2. Инструмент Leaks — стукач прямой наводки

Запускаешь: Product > Profile > Leaks.

  • Этот, блядь, сразу орёт, если нашёл утечку. Чаще всего он находит не наши, свифтовые циклы, а какую-нибудь старую шнягу на C, где указатели забыли отпустить. Но тоже полезно.

3. Ручная проверка — для тех, кто не доверяет автоматам

Тут уже самому надо мозги включать, а то так и будешь с утра до вечера на графики смотреть.

  • Проверка вызова deinit — святое дело:

    class MyViewController: UIViewController {
        deinit {
            print("MyViewController deallocated") // Если эту надпись не видишь — всё, пиздец, он живёт вечно. Значит, кто-то его держит.
        }
    }
  • Типичные грабли, на которые все наступают:

    • Замыкания: Ну ёпта, классика ж! Забыл написать [weak self] — и всё, приехали. self держит замыкание, замыкание держит self. Вечная любовь, блядь, в памяти.
    • Делегаты: Если объявил делегат как strong — готовься к сюрпризам. Должен быть weak, и точка. Иначе контроллеры друг друга как два мудака в обнимку и не отпустят.
    • Таймеры: Timer — тот ещё пидарас шерстяной. Он target держит крепко. Не инвалидировал в deinit — считай, подарил ему бессмертие. Либо переходи на таймер с closure-based API.
    • Уведомления (NotificationCenter): Подписался, а отписаться забыл. Типа «ой, да похуй, система сама почистит». Не почистит, блядь! Особенно если iOS версии старые. Удалил наблюдателя — спи спокойно.
  • Косвенный анализ — для параноиков: Есть в Xcode кнопка Debug Memory Graph (паутинка). Тыкаешь в неё, когда приложение в нужном состоянии, и смотришь на граф объектов. Можно ткнуть в любой и увидеть, кто на него ссылается. Иногда находишь такие неожиданные связи, что волосы дыбом встают — «а ты чё, сука, здесь забыл?».

Вот и весь сказ. Сначала deinit проверь, потом Instruments запусти, а там уже смотри, что за мудак память просирает. Удачи, не проеби!