Обнаружение и исправление утечек памяти (Memory Leaks) мобильного приложения

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Обнаружение и исправление утечек памяти (Memory Leaks) мобильного приложения
Сложная
~3-5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Обнаружение и исправление утечек памяти (Memory Leaks) мобильного приложения

Приложение убивает iOS, когда пользователь открывает и закрывает экран с картой 20 раз подряд. Crash log содержит Terminated due to memory pressure. В Instruments → Allocations видно: каждое открытие MapViewController добавляет ~12 MB в heap и эти 12 MB никогда не освобождаются. После 20 открытий — 240 MB только от экрана карты. Это утечка памяти — не «возможно», а точно.

Механика утечек: почему объекты не освобождаются

Retain cycles на iOS (ARC)

ARC считает сильные ссылки. Если A держит B, а B держит A — ни один не достигнет нулевого счётчика и никогда не освободится. Самые частые паттерны:

Closure без [weak self]:

// УТЕЧКА
viewModel.onDataLoaded = {
    self.tableView.reloadData() // сильная ссылка на self
}

// ПРАВИЛЬНО
viewModel.onDataLoaded = { [weak self] in
    self?.tableView.reloadData()
}

Timer:

// УТЕЧКА — Timer удерживает target сильно
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self,
                              selector: #selector(tick), userInfo: nil, repeats: true)

При закрытии ViewController timer продолжает работать и удерживает ViewController. Решение — Timer.scheduledTimer(withTimeInterval:repeats:block:) с [weak self] в block, и обязательный timer.invalidate() в deinit.

Delegate без weak:

// УТЕЧКА
protocol DataDelegate: AnyObject { func didLoad() }
class DataService {
    var delegate: DataDelegate? // должен быть weak!
}

Если DataService живёт дольше делегата или оба держат друг друга — утечка. weak var delegate: DataDelegate? — обязательно.

Утечки на Android

Context leak — самая распространённая:

// УТЕЧКА — Activity Context в singleton
object AppRepository {
    private var context: Context? = null
    fun init(ctx: Context) { context = ctx } // ctx — Activity
}

Activity не освобождается пока живёт Repository. Используем только applicationContext в singleton-объектах.

Anonymous inner class + Handler:

// УТЕЧКА — анонимный класс неявно держит ссылку на Activity
private val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
    updateUI() // this — неявная ссылка на Activity
}, 5000)

Решение: WeakReference<MyActivity> или lifecycleScope.launch { delay(5000); updateUI() } — coroutine отменяется вместе с lifecycle.

LiveData observers без removeObserver: В Fragment подписываемся на ViewModel.liveData.observe(this, ...). Если this — не viewLifecycleOwner а сам Fragment — observer живёт весь lifecycle Fragment-а, включая периоды когда View разрушена. При пересоздании View — добавляется второй observer. Итого N observers после N пересозданий.

Диагностика: инструменты

LeakCanary (Android) — de facto стандарт. Добавляем одну зависимость в debug build, он автоматически отслеживает Activity, Fragment, View, ViewModel. При обнаружении утечки — уведомление с полным retain tree. Обязателен в любом Android-проекте.

Instruments → Leaks (iOS) — строит граф объектов и ищет циклы. Запускаем сценарий 10–15 раз, ждём когда Leaks покраснеет. Клик на утечку — полный стек объектов с retain-путём.

Instruments → Allocations, Generation Analysis — для logical leaks (объекты без цикличных ссылок, но которые накапливаются). Mark generation перед действием → выполнить действие → посмотреть что добавилось и не ушло.

Android Studio Memory Profiler → Heap Dump — снимок heap с путём до GC root для каждого объекта. Ищем Activity экземпляры — их не должно быть более одного (активного).

Кейс: RxJava Disposable без dispose

Flutter-разработчик перешёл на Android и написал RxJava-код с Observable.interval. Подписка создавалась в onCreate, Disposable нигде не сохранялся. При каждой ротации экрана создавался новый Observer, старый продолжал работать. Через 10 ротаций — 10 активных потоков. LeakCanary нашёл это за 2 минуты: retained Activity через Observable → Observer → Activity reference.

Решение: CompositeDisposable, добавляем все подписки, вызываем disposables.clear() в onStop() или onDestroy().

Что делаем в рамках услуги

  • Добавляем LeakCanary в debug-сборку Android, настраиваем прогон тестовых сценариев
  • Проводим сессии Instruments Leaks + Allocations для iOS по всем ключевым экранам
  • Анализируем все retain-пути найденных утечек
  • Исправляем: weak references, timer invalidation, proper closure capture, observer lifecycle
  • Добавляем deinit / onDestroy логирование для регрессионного контроля

Сроки

Диагностика утечек памяти — 1–3 дня. Исправление выявленных утечек — 2–7 дней в зависимости от количества и запущенности проблемы.