Профілювання пам'яті мобільної програми
Програма працює нормально перші 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 тижнів залежно від глибини проблеми.







