← Назад к вопросам
Как понять что кто-то ссылается на объект
2.0 Middle🔥 181 комментариев
#JVM и память#Производительность и оптимизация
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как понять, что кто-то ссылается на объект в Android/Java
В Java/Kotlin объект существует в памяти, пока на него есть ХОТЯ БЫ ОДНА ссылка. Проверить, на объект ли ссылаются, можно несколькими способами.
1. Использование Android Studio Profiler
Этот способ — самый надёжный для поиска утечек памяти:
- Run → Profile → Memory
- Нажми Record → выполни сценарий → нажми Stop
- Используй Dump Java Heap
- В Heap Dump найди свой класс
- Посмотри Retain Path → увидишь все ссылки на объект
2. LeakCanary (библиотека)
Автоматически находит утечки:
// Добавить в build.gradle
dependencies {
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.14")
}
LeakCanary автоматически обнаружит, что объект не был собран сборщиком мусора, и покажет весь путь ссылок.
3. Debug печать и WeakReference
class MyClass
val strongRef = MyClass() // Сильная ссылка
val weakRef = WeakReference(strongRef) // Слабая ссылка
// Проверка: есть ли ссылки на объект?
println(weakRef.get()) // Выведет объект, если он жив
strongRef = null
println(weakRef.get()) // Выведет null, если GC собрал объект
4. Типичные места утечек памяти
❌ Анонимные классы (содержат скрытую ссылку на Activity):
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// УТЕЧКА! MyTask содержит ссылку на Activity
val task = object : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg p0: Void?) = null
}
}
}
✅ Правильно — используй static или Lifecycle-aware компоненты:
// Используй ViewModel вместо AsyncTask
class MyViewModel : ViewModel() {
fun loadData() {
// Здесь нет ссылки на Activity
}
}
5. Listener и Callback
class EventBus {
private val listeners = mutableListOf<(String) -> Unit>()
fun subscribe(listener: (String) -> Unit) {
listeners.add(listener) // УТЕЧКА! Слушатель привязан
}
fun unsubscribe(listener: (String) -> Unit) {
listeners.remove(listener) // Обязательно удалить!
}
}
6. Static переменные
class ImageCache {
companion object {
private val cache = mutableMapOf<String, Bitmap>()
// УТЕЧКА! Bitmap живут вечно, пока приложение запущено
}
}
7. Context references в Singleton
// ❌ УТЕЧКА
object MyManager {
lateinit var context: Context
fun init(context: Context) {
this.context = context // Activity никогда не будет собрана
}
}
// ✅ Правильно
object MyManager {
fun init(context: Context) {
val appContext = context.applicationContext // Используй ApplicationContext
}
}
Инструменты для анализа
| Инструмент | Для чего |
|---|---|
| Android Profiler | Визуализация утечек в реальном времени |
| LeakCanary | Автоматическое обнаружение утечек |
| MAT (Memory Analyzer) | Анализ heap dump |
| Logcat | GC логи (adb logcat | grep GC) |
Итог
Чтобы понять, есть ли ссылки на объект:
- Используй Android Profiler для поиска в рабочем приложении
- Добавь LeakCanary для автоматического обнаружения
- Проверь Retain Path в Heap Dump
- Избегай типичных утечек: контекст в синглтонах, listener без unsubscribe, static кэши