В Android‑приложении наблюдается утечка памяти при хранении Context в статическом поле, пример: public class MyActivity extends Activity { private static Drawable bg; protected void onCreate(...) { bg = getResources().getDrawable(R.drawable.bg); } } — в чём проблема, как исправить и какими инструментами искать подобные утечки
Проблема - Статическое поле является GC-root: если в него положить Drawable, который ссылается на Context/Activity (через Resources, Theme, callback и т.д.), Activity не будет освобождена — утечка памяти. - В вашем примере `bg` удерживает ресурс, связанный с Activity, и Activity не может быть собрана сборщиком мусора. Как исправить (кратко и по делу) - Не храните Context, View или Drawable, полученные из Activity, в static-полях. - Если нужен глобальный Context, используйте application context: `getApplicationContext()` или храните `Application` (но помните про тему — application context не содержит Activity theme). Пример безопасной загрузки: ``` Drawable bg = ContextCompat.getDrawable(getApplicationContext(), R.drawable.bg); ``` - Для кэша используйте LruCache или WeakReference вместо сильной статической ссылки: ``` private static WeakReference bgRef; Drawable bg = bgRef != null ? bgRef.get() : null; if (bg == null) { bg = ContextCompat.getDrawable(getApplicationContext(), R.drawable.bg); bgRef = new WeakReference(bg); } ``` - Лучше хранить лишь идентификатор ресурса (например `int resId`) в статике и загружать Drawable при необходимости. - Для больших Bitmap используйте LruCache и освобождайте/рецайклируйте при необходимости (для старых API). - Не пытайтесь «обнулять» статические поля в onDestroy как основное решение — лучше не держать их вообще. Инструменты для поиска утечек - LeakCanary — автоматическое обнаружение утечек в приложении, простая интеграция. - Android Studio Memory Profiler — запись heap dump, отслеживание объектов, view roots, allocation tracking. - Захват heap dump + анализ в MAT (Eclipse Memory Analyzer) — просмотр путей от GC roots до утечек (реализует подсказки «leak suspects»). - adb/bugreport и `hprof-conv` для конвертации дампов, если нужно анализировать вне IDE. - StrictMode (частично) и Allocation Tracker для локализации подозрительных аллокаций (не прямой детектор утечек, но полезен). Короткое резюме - Не храните Context/Activity/Views/Drawable из Activity в static. Используйте application context, слабые ссылки, LruCache или просто храните resId и подгружайте ресурс по необходимости. Для поиска — LeakCanary, Memory Profiler и MAT.
- Статическое поле является GC-root: если в него положить Drawable, который ссылается на Context/Activity (через Resources, Theme, callback и т.д.), Activity не будет освобождена — утечка памяти.
- В вашем примере `bg` удерживает ресурс, связанный с Activity, и Activity не может быть собрана сборщиком мусора.
Как исправить (кратко и по делу)
- Не храните Context, View или Drawable, полученные из Activity, в static-полях.
- Если нужен глобальный Context, используйте application context: `getApplicationContext()` или храните `Application` (но помните про тему — application context не содержит Activity theme).
Пример безопасной загрузки:
```
Drawable bg = ContextCompat.getDrawable(getApplicationContext(), R.drawable.bg);
```
- Для кэша используйте LruCache или WeakReference вместо сильной статической ссылки:
```
private static WeakReference bgRef;
Drawable bg = bgRef != null ? bgRef.get() : null;
if (bg == null) {
bg = ContextCompat.getDrawable(getApplicationContext(), R.drawable.bg);
bgRef = new WeakReference(bg);
}
```
- Лучше хранить лишь идентификатор ресурса (например `int resId`) в статике и загружать Drawable при необходимости.
- Для больших Bitmap используйте LruCache и освобождайте/рецайклируйте при необходимости (для старых API).
- Не пытайтесь «обнулять» статические поля в onDestroy как основное решение — лучше не держать их вообще.
Инструменты для поиска утечек
- LeakCanary — автоматическое обнаружение утечек в приложении, простая интеграция.
- Android Studio Memory Profiler — запись heap dump, отслеживание объектов, view roots, allocation tracking.
- Захват heap dump + анализ в MAT (Eclipse Memory Analyzer) — просмотр путей от GC roots до утечек (реализует подсказки «leak suspects»).
- adb/bugreport и `hprof-conv` для конвертации дампов, если нужно анализировать вне IDE.
- StrictMode (частично) и Allocation Tracker для локализации подозрительных аллокаций (не прямой детектор утечек, но полезен).
Короткое резюме
- Не храните Context/Activity/Views/Drawable из Activity в static. Используйте application context, слабые ссылки, LruCache или просто храните resId и подгружайте ресурс по необходимости. Для поиска — LeakCanary, Memory Profiler и MAT.