Ответ
Да, приходилось. Основные методы:
- Использование
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 класс всякое говно размером с бегемота. Иначе твое приложение накроется медным тазом при первом же серьезном повороте экрана. Волнение ебать, когда видишь, как оно крешится у пользователей из-за такой ерунды.