Как работает GarbageCollector?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает GarbageCollector?
GarbageCollector (GC) — это механизм автоматического управления памятью в Java и Kotlin, который освобождает память, занятую объектами, на которые больше нет ссылок. Это критически важная система для стабильности приложений.
Базовый принцип работы
Метод Reference Counting:
GC отслеживает ссылки на объекты. Когда ссылок нет — объект удаляется:
val user = User("Alice") // Объект создан
// Ссылка на объект: 1
val user2 = user // Объект всё ещё существует
// Ссылок: 2
user = null // Удалили ссылку
// Ссылок: 1
user2 = null // Удалили последнюю ссылку
// Ссылок: 0 -> GC удалит объект
Поколения объектов (Generational GC)
JVM использует поколенческую модель — молодые объекты удаляются чаще:
Young Generation (молодое поколение):
├── Eden — где создаются новые объекты
├── Survivor Space 1 — пережившие первую GC
└── Survivor Space 2 — пережившие несколько GC
Old Generation (старое поколение):
└── Объекты, пережившие много сборок мусора
Типы сборок мусора
1. Minor GC (молодое поколение)
val objects = mutableListOf<String>()
for (i in 1..1000000) {
objects.add("String_$i") // Много объектов создаётся в Eden
}
// Minor GC удалит неиспользуемые строки из молодого поколения
Самая частая, самая быстрая.
2. Major GC (старое поколение)
var bigData: ByteArray? = ByteArray(10 * 1024 * 1024) // 10 MB
// Используем данные...
bigData = null
// Major GC удалит большой объект из старого поколения
Реже, но медленнее (может заморозить приложение на 100+ мс).
3. Full GC
// Полная сборка мусора всей heap
// Самая долгая операция
// На Android это может привести к lag'am
Алгоритмы GC
Mark and Sweep (отметь и удали):
Шаг 1: Mark (отметить живые объекты)
├── GC начинает с корневых ссылок (переменные в stack)
├── Отмечает все объекты, которые доступны
└── Остальные объекты считаются мусором
Шаг 2: Sweep (удалить мусор)
├── Удаляет неотмеченные объекты
└── Освобождает память
Проблемы в Android
1. Jank (заикание) из-за GC
// Создание множества объектов в onDraw()
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// ПЛОХО: GC может сработать и заморозить UI
for (i in 0..1000) {
val paint = Paint() // Много объектов
canvas.drawCircle(x, y, 10f, paint)
}
}
// ХОРОШО: переиспользовать объекты
private val paint = Paint()
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
for (i in 0..1000) {
canvas.drawCircle(x, y, 10f, paint) // Один объект
}
}
2. Утечка памяти
// ПЛОХО: утечка из-за сильной ссылки
class MyActivity : AppCompatActivity() {
companion object {
var instance: MyActivity? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
instance = this // Activity never GC'd!
}
}
// ХОРОШО: используй WeakReference если нужно
import java.lang.ref.WeakReference
companion object {
var instance: WeakReference<MyActivity>? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
instance = WeakReference(this) // Может быть собран
}
3. GC thrashing (частые сборки)
// ПЛОХО: частое создание объектов
fun processData(items: List<Item>) {
items.forEach { item ->
val temp = convertToString(item) // Создание каждой итерации
processString(temp)
}
}
// ХОРОШО: переиспользовать StringBuilder
fun processData(items: List<Item>) {
val builder = StringBuilder()
items.forEach { item ->
builder.clear()
builder.append(item)
processString(builder.toString())
}
}
Виды ссылок в Java/Kotlin
1. Strong Reference (сильная ссылка)
val obj = MyObject() // Сильная ссылка, объект не удалится
2. Weak Reference (слабая ссылка)
import java.lang.ref.WeakReference
var obj: MyObject? = MyObject()
val weak = WeakReference(obj)
obj = null
// GC может удалить объект
println(weak.get()) // null если объект был удалён
3. Soft Reference (мягкая ссылка)
import java.lang.ref.SoftReference
val soft = SoftReference(myBitmap)
// Удалится, если не хватает памяти
Оптимизация для Android
1. Профилирование с Profiler
Android Studio → Profiler → Memory tab показывает сборки мусора.
2. Минимизация объектов в критических местах
// В RecyclerView.Adapter
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
holder.bind(item) // Не создавай новые объекты здесь!
}
3. Используй Object Pool для часто используемых объектов
class ObjectPool<T>(private val factory: () -> T) {
private val available = mutableListOf<T>()
fun acquire(): T = if (available.isNotEmpty()) {
available.removeAt(0)
} else {
factory()
}
fun release(obj: T) {
available.add(obj)
}
}
GC Events в Logcat
// Примеры сообщений
I/GC: Explicit concurrent mark sweep GC freed 64MB
I/GC: Alloc concurrent mark sweep GC freed 20MB
Частые GC означают проблемы с памятью.
Best practices
- Минимизируй создание объектов в критических местах (onDraw, onScroll)
- Используй пулы объектов для частого переиспользования
- Избегай утечек памяти — отписывайся от событий
- Профилируй память регулярно
- Используй Weak/Soft References когда нужно
- Очищай ссылки в onDestroy()
Заключение
GarbageCollector — это критически важная система, которая управляет памятью автоматически. На Android нужно быть осторожным, чтобы избежать частых GC и утечек памяти, которые приводят к lag'ам и краш'ам. Понимание того, как работает GC, помогает написать более эффективный код.