Приходилось ли исследовать «утечки» памяти? Какие инструменты использовали для этого?android-224

Основные подходы к анализу утечек памяти

1. Android Profiler

Использование:

  • Встроен в Android Studio
  • Позволяет в реальном времени отслеживать:
    • Выделение памяти
    • Создание и уничтожение объектов
    • Активные ссылки

Типичный сценарий:

  1. Запускаем запись аллокаций
  2. Воспроизводим проблемный сценарий
  3. Анализируем стек вызовов удерживающих объектов
Memory Profiler → Record allocations → Force GC → Analyze

2. LeakCanary

Особенности:

  • Автоматическое обнаружение утечек
  • Наглядные отчеты с цепочками ссылок
  • Простая интеграция

Пример настройки:

dependencies {
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
}

Что обнаруживает:

  • Неосвобожденные Activity/Fragment
  • Удерживаемые View/Context
  • Синглтоны с ссылками на View

3. MAT

Для сложных случаев:

  • Анализ heap dump
  • Поиск retaining paths
  • Расчет размера удерживаемой памяти

Процесс работы:

  1. Снимаем heap dump:
    adb shell am dumpheap <PID> /data/local/tmp/heap.hprof
    
  2. Конвертируем для MAT:
    hprof-conv heap.hprof converted.hprof
    
  3. Анализируем в Eclipse MAT

4. Android Studio Heap Dump

Быстрый анализ:

  • Правка по heap dump в Android Studio
  • Поиск по классам/пакетам
  • Просмотр ссылочных цепочек

Типичные сценарии утечек

1. Неправильные ссылки на Context

class Singleton(context: Context) {
    // Плохо: удерживаем контекст активности
    private val badContext = context

    // Хорошо: использовать applicationContext
    private val goodContext = context.applicationContext
}

2. Коллбэки без отписки

class MyActivity : AppCompatActivity() {
    private val listener = { /*...*/ }

    override fun onCreate() {
        someObject.setListener(listener) // Утечка активности
    }

    // Решение: WeakReference или явная отписка
}

3. Долгоживущие View ссылки

object ViewHolder {
    var dangerousView: View? = null // Удерживает всю иерархию
}

Продвинутые техники

1. Анализ через Allocation Tracker

  • Запись всех аллокаций за период
  • Выявление "тяжелых" объектов

2. Использование WeakReference

class SafeReference(activity: Activity) {
    private val weakRef = WeakReference(activity)

    fun doSomething() {
        weakRef.get()?.let { activity ->
            // Безопасная работа с активностью
        }
    }
}

3. Тестирование на утечки

@RunWith(AndroidJUnit4::class)
class MemoryLeakTest {
    @Test
    fun checkActivityLeak() {
        val scenario = launchActivity<MainActivity>()
        scenario.recreate() // Эмулируем поворот экрана
        scenario.onActivity { activity ->
            assertFalse(isObjectRetained(activity))
        }
    }
}

Практические советы по профилактике

  1. Правила работы с Context:

    • Всегда предпочитать applicationContext
    • Не хранить Context в статических полях
  2. Жизненный цикл компонентов:

    • Очищать ссылки в onDestroy()
    • Использовать viewModelScope для корутин
  3. Паттерны проектирования:

    • Внедрение зависимостей вместо синглтонов
    • Делегирование вместо наследования View

Резюмируем:

Для эффективного поиска утечек памяти в Android требуется комбинация инструментов - LeakCanary для автоматического обнаружения, Memory Profiler для интерактивного анализа и MAT для глубокого исследования сложных случаев. Профилактика утечек должна быть частью ежедневной практики разработки через соблюдение правил работы с контекстом и жизненным циклом компонентов.