Профилирование памяти мобильного приложения
Приложение работает нормально первые 5 минут, потом начинает подтормаживать, а через 15 минут — вылетает. NSLog: Received memory warning. Это классическая история постепенной утечки памяти: что-то удерживает объекты, которые должны освобождаться, RSS растёт, система убивает процесс. Найти, что именно удерживает — задача профилировщика памяти.
Инструменты и что они показывают
Xcode Instruments — Leaks и Allocations
Allocations — показывает все live-объекты в памяти в каждый момент времени. Самый полезный вид — «Generation Analysis»: делаем Mark Generation перед действием, выполняем действие несколько раз, смотрим что накапливается между генерациями и не освобождается.
Сценарий: открываем DetailViewController, закрываем, повторяем 10 раз. В Allocations — каждый раз добавляется PhotoProcessingService объект, который не освобождается. Переходим к Leaks инструменту — он строит граф объектов в памяти и находит циклические ссылки. Видим: DetailViewController → PhotoProcessingService → DetailViewController через delegate без weak. Один weak var delegate — и утечка устранена.
Heap Shot в Allocations — снимок кучи в момент времени. Сравниваем два снимка до и после операции. Разница = объекты, которые остались в памяти. Это точнее, чем Leaks, для нахождения logical leaks (объекты в памяти без циклических ссылок, но которые уже не нужны — например, старые элементы в неограниченном кэше).
Android Studio Memory Profiler
Показывает heap в реальном времени: Java heap, Native heap, Stack, Graphics. Кнопка Capture heap dump — снимок всех live-объектов с path to GC root. По каждому классу видно количество экземпляров и суммарный retained size.
Типичная находка: Bitmap объекты в Native heap. До Android 8 битмапы хранились в Java heap и собирались GC. С Android 8+ — в native heap, и Memory Profiler показывает их отдельно. Если native heap растёт — ищем Bitmap без recycle() или Glide/Picasso с отключённым LRU-кэшем.
Allocation tracking — запись всех аллокаций за период. Тяжёлый режим, включаем только для конкретного сценария. Показывает стек вызовов для каждой аллокации — видно, кто создаёт объекты в цикле на hot path.
LeakCanary — обязательный инструмент на Android
LeakCanary автоматически обнаруживает утечки Activity, Fragment, ViewModel, LiveData и других компонентов. Достаточно добавить зависимость в debug flavor — он работает в фоне и показывает уведомление с полным стеком при обнаружении утечки. На iOS аналог — LifetimeTracker или FBRetainCycleDetector.
// build.gradle (debug)
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
Без дополнительной настройки. Работает.
Наиболее частые паттерны утечек
Статические ссылки на Context (Android). companion object { val instance = MyHelper(context) } — если context это Activity, а не applicationContext — утечка Activity при ротации.
Closure в Swift без [weak self]. networkService.fetch { data in self.update(data) } — если closure сохраняется (например, в массив pending callbacks) — сильная ссылка на self предотвращает освобождение.
NotificationCenter подписки без отписки. В iOS до Swift 5.3 addObserver без removeObserver — классическая утечка. С NotificationCenter.default.publisher(for:) через Combine и хранением в cancellables — проблема решена автоматически.
Handler в Android. Handler(Looper.getMainLooper()) с postDelayed удерживает Activity через implicit inner class reference. Используем WeakReference<Activity> или переходим на lifecycleScope.launch { delay(ms) ... }.
Кейс: 200 MB утечка за сессию
Android-приложение с картами: за 20 минут навигации память вырастала с 80 до 280 MB. Memory Profiler показал — MapTile объекты (растровые тайлы карты) не освобождались после ухода с карточного экрана. MapView не вызывал onDestroy потому что Fragment с картой находился в backstack без destroyView. Замена на FragmentTransaction.remove() вместо addToBackStack() + ручная очистка mapView.onDestroy() — утечка устранена.
Этапы профилирования памяти
- Baseline: измеряем потребление памяти в состоянии покоя и под нагрузкой
- Stress test: повторяем ключевые сценарии 20–50 раз, смотрим тренд роста памяти
- Heap dump analysis: ищем объекты с неожиданно высоким retained size
- Leak confirmation: воспроизводим утечку с LeakCanary / Instruments Leaks
- Fix & verify: исправляем, проверяем что RSS стабилизировался
Сроки
Профилирование и анализ памяти — 2–3 дня. Исправление найденных утечек — от 1 дня до 2 недель в зависимости от глубины проблемы.







