← Назад к вопросам

Приведи пример утечки Context

1.0 Junior🔥 191 комментариев
#JVM и память#Android компоненты

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример утечки Context в Android

Утечка Context — частая проблема в разработке под Android, когда Activity, Service или Application контекст удерживается в памяти дольше необходимого, препятствуя сборке мусора. Это может привести к утечкам памяти, OutOfMemoryError и некорректной работе приложения. Основная причина — неправильное хранение контекста в статических полях или долгоживущих объектах (например, в синглтонах или фоновых потоках), которые переживают жизненный цикл компонента.

Конкретный пример утечки

Рассмотрим типичный случай: создание синглтона (например, менеджера данных), который хранит ссылку на Context для доступа к ресурсам или системным сервисам. Если передать в него контекст Activity, а не Application, это приведёт к утечке.

// НЕПРАВИЛЬНО: синглтон с утечкой Context
class DataManager private constructor(context: Context) {
    private val appContext: Context = context.applicationContext
    private val sharedPreferences: SharedPreferences
    
    init {
        // Хранение контекста, переданного из Activity
        sharedPreferences = context.getSharedPreferences("app_data", Context.MODE_PRIVATE)
    }
    
    companion object {
        private var instance: DataManager? = null
        
        fun getInstance(context: Context): DataManager {
            if (instance == null) {
                instance = DataManager(context) // Передаётся контекст Activity
            }
            return instance!!
        }
    }
    
    fun saveData(key: String, value: String) {
        sharedPreferences.edit().putString(key, value).apply()
    }
}

При вызове DataManager.getInstance(this) из Activity синглтон сохранит ссылку на её контекст. Поскольку синглтон живёт всё время работы приложения, Activity не сможет быть уничтожена сборщиком мусора даже после закрытия (например, при повороте экрана). Это классическая утечка, которую можно обнаружить через Android Profiler или LeakCanary.

Как исправить утечку

  1. Использование Application Context: Для синглтонов всегда передавайте контекст приложения, доступный через context.applicationContext. Он не привязан к жизненному циклу UI-компонентов.
  2. Использование WeakReference: Если нужен контекст Activity (например, для диалогов), применяйте WeakReference, но с осторожностью.
  3. Очистка ссылок: В onDestroy() Activity удаляйте ссылки на контекст в сторонних объектах.

Исправленный код:

// ПРАВИЛЬНО: безопасный синглтон
class SafeDataManager private constructor(context: Context) {
    private val appContext: Context = context.applicationContext // Используем Application Context
    private val sharedPreferences: SharedPreferences
    
    init {
        sharedPreferences = appContext.getSharedPreferences("app_data", Context.MODE_PRIVATE)
    }
    
    companion object {
        @Volatile
        private var instance: SafeDataManager? = null
        
        fun getInstance(context: Context): SafeDataManager {
            return instance ?: synchronized(this) {
                instance ?: SafeDataManager(context).also { instance = it }
            }
        }
    }
}

Ключевые моменты:

  • Application Context безопасен для долгоживущих операций (доступ к ресурсам, SharedPreferences).
  • Activity Context используйте только для задач, связанных с UI (показ диалогов, привязка к жизненному циклу).
  • Всегда проверяйте, не храните ли вы контекст в статических полях, фоновых потоках или колбэках (например, в Listeners или Callbacks), которые не отписываются вовремя.

Профилактика утечек

  • LeakCanary: Интегрируйте библиотеку для автоматического обнаружения утечек.
  • Android Profiler: Анализируйте память в реальном времени.
  • Правила:
    • Избегайте нестатических вложенных классов в Activity (они хранят ссылку на внешний класс).
    • Для Handler используйте WeakReference или viewModelScope в архитектуре MVVM.
    • Отписывайтесь от BroadcastReceiver, EventBus в onDestroy().

Утечки Context снижают производительность и стабильность приложения, поэтому важно применять паттерны безопасной работы с памятью с самого начала разработки.