← Назад к вопросам
Для чего нужен Heap?
1.8 Middle🔥 241 комментариев
#JVM и память#Производительность и оптимизация
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Heap (куча) в Android
Определение
Heap — это область памяти в JVM, где выделяются объекты во время выполнения программы. Это один из самых критических ресурсов Android приложения, так как память телефона ограничена.
Назначение Heap
- Хранение объектов — все Object'ы (классы) выделяются на Heap
- Управление памятью — Garbage Collector автоматически удаляет неиспользуемые объекты
- Динамическое выделение — размер объекта известен только во время выполнения
Отличие от Stack
fun example() {
val primitiveInt = 42 // Stack: примитивный тип, быстро
val list = mutableListOf(1, 2, 3) // List объект на Heap
// Stack содержит ссылку на объект в Heap
}
Heap в Android
Каждое приложение получает 限制 размер Heap:
- Типичный размер: 128-512 MB (зависит от устройства)
- Можно проверить:
val runtime = Runtime.getRuntime()
val maxMemory = runtime.maxMemory() / 1024 / 1024 // в МБ
val usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024
Log.d("Memory", "Max: $maxMemory MB, Used: $usedMemory MB")
Проблемы с Heap
1. OutOfMemoryError (OOM)
Самая частая ошибка в Android — когда Heap переполняется:
// ПЛОХО: создание большого списка
val images = mutableListOf<Bitmap>()
for (i in 0..10000) {
images.add(loadImageAsBitmap("image_$i.jpg")) // OOM!
}
// ХОРОШО: обработка по одной
for (i in 0..10000) {
val bitmap = loadImageAsBitmap("image_$i.jpg")
processImage(bitmap)
bitmap.recycle() // освобождаем память
}
2. Memory Leak
Основной источник утечек — неправильные ссылки на Activity/Fragment:
// УТЕЧКА: анонимный класс держит ссылку на Activity
class ImageLoader(private val activity: Activity) {
fun loadImage(url: String) {
thread {
val bitmap = downloadImage(url)
activity.runOnUiThread { // если activity была destroyed?
activity.imageView.setImageBitmap(bitmap) // УТЕЧКА!
}
}
}
}
// ПРАВИЛЬНО: используем WeakReference или Lifecycle
class ImageLoader(private val lifecycleOwner: LifecycleOwner) {
fun loadImage(url: String) {
lifecycleOwner.lifecycleScope.launch {
val bitmap = withContext(Dispatchers.IO) {
downloadImage(url)
}
imageView.setImageBitmap(bitmap) // безопасно
}
}
}
GC (Garbage Collector)
Автоматически удаляет неиспользуемые объекты:
fun example() {
val tempObject = HeavyObject() // создание на Heap
doSomething(tempObject)
} // tempObject выходит из scope
// GC удалит tempObject, освободив память
Оптимизация использования Heap
1. Object Pooling (переиспользование)
class ObjectPool<T> {
private val pool = mutableListOf<T>()
fun acquire(factory: () -> T): T {
return if (pool.isNotEmpty()) pool.removeAt(0) else factory()
}
fun release(obj: T) {
pool.add(obj)
}
}
// Использование
val stringBuilder = "StringBuilder".let { pool.acquire { StringBuilder() } }
try {
stringBuilder.append("Hello")
} finally {
pool.release(stringBuilder)
}
2. Lazy Loading
// ПЛОХО: загружаем всё сразу
val allUsers = repository.getAllUsers() // может быть гигабайты данных
// ХОРОШО: загружаем по частям
val usersPaginated = repository.getUsers(page = 1, pageSize = 20)
3. Bitmap Optimization
fun loadImageOptimized(context: Context, resourceId: Int, targetWidth: Int): Bitmap {
val options = BitmapFactory.Options().apply {
inSampleSize = 2 // загружаем в 2 раза меньше
}
return BitmapFactory.decodeResource(context.resources, resourceId, options)
}
// или используем Glide/Picasso
Glide.with(context)
.load(imageUrl)
.override(targetWidth, targetHeight)
.into(imageView)
4. Listener Management
// УТЕЧКА: забыли unsubscribe
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedViewModel.data.observe(this) { data -> // подписались
updateUI(data)
}
// при destroy фрагмента Observer удалится автоматически
}
}
Инструменты профилирования
1. Android Studio Profiler
View → Tool Windows → Profiler
↓
Memory tab → Live Allocation
↓
Найти утечки и OOM
2. LeakCanary
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}
// LeakCanary автоматически обнаружит утечки
3. MAT (Memory Analyzer Tool)
Анализ Heap dumps для поиска утечек
Практические советы
- Всегда очищайте ресурсы — Bitmap.recycle(), closeables
- Используйте Weak/Soft References для кэшей
- Профилируйте память — не гадайте
- Object pooling для частых аллокаций
- Lazy initialization — создавайте объекты только при необходимости
- Избегайте анонимных классов в тяжёлых операциях
Вывод
Heap — это ограниченный ресурс, требующий постоянного контроля. Правильное управление памятью — залог стабильного и быстрого приложения без крашей и утечек.