Приходилось ли оптимизировать память в Android приложении

Ответ

Да, приходилось. Основные методы:

  • Использование WeakReference для кеширования, чтобы GC мог очистить объекты при нехватке памяти.
WeakReference<Bitmap> weakBitmap = new WeakReference<>(bitmap);
  • Оптимизация Bitmap через inSampleSize, BitmapFactory.Options и библиотеки типа Glide/Picasso.

  • Анализ утечек памяти через LeakCanary и Android Profiler.

  • Очистка ресурсов в onDestroy()/onStop(), отмена подписок (RxJava/Coroutines).

  • Использование ArrayMap/SparseArray вместо HashMap для примитивных ключей.

Пример:

val sparseArray = SparseArray<String>().apply {
    put(1, "value") // Экономит память vs HashMap<Int, String>
}

Также важно избегать статических контекстов и больших объектов в Application.

Ответ 18+ 🔞

А, блядь, вот это вопрос! Да, конечно, приходилось, и не раз, ёпта. Прямо как будто на дворе 2002-й год, и ты пытаешься запихнуть овердохуища фоток в память телефона, который и так уже бздит от натуги.

Основные методы, которые спасали жопу:

  • Использование WeakReference для кеширования. Это как дать объекту пожить на птичьих правах. GC смотрит на него и думает: "Ну, слабая ссылка, да похуй", и когда память кончается — хуй с горы, объект в топку. Красота.
WeakReference<Bitmap> weakBitmap = new WeakReference<>(bitmap);
  • Оптимизация Bitmap. Это святое, чувак. Без inSampleSize и BitmapFactory.Options ты сожрёшь всю оперативку одной картинкой. Библиотеки типа Glide — это вообще манна небесная, они там под капотом такое вытворяют, что сам от себя охуеешь.
  • Анализ утечек памяти через LeakCanary и Profiler. Без этого — пиши пропало. Запускаешь LeakCanary, а он тебе: "Э, сабака сука, тут у тебя активити после ротации живет вечно!" И показываешь пальцем, где твой статический листенер всё проебал.
  • Очистка ресурсов. onDestroy() — не для красоты, блядь. Туда все отписки от Rx-потоков или корутин, закрытие курсоров, остановку анимаций. Иначе получишь хитрая жопа, которая тихо сосёт память.
  • Использование ArrayMap/SparseArray вместо HashMap. Вот это реально экономит, когда ключи — примитивы. HashMap для Int ключей — это пиздопроебибна по памяти, там же объекты-обёртки создаются. А SparseArray — легковесный красавчик.

Пример, чтобы было понятно:

val sparseArray = SparseArray<String>().apply {
    put(1, "value") // Экономит память vs HashMap<Int, String> — реально чувствуется
}

И главное, блядь, — избегать статических контекстов и не пихать в Application класс всякое говно размером с бегемота. Иначе твое приложение накроется медным тазом при первом же серьезном повороте экрана. Волнение ебать, когда видишь, как оно крешится у пользователей из-за такой ерунды.