← Назад к вопросам

Как понять что кто-то ссылается на объект

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
LogcatGC логи (adb logcat | grep GC)

Итог

Чтобы понять, есть ли ссылки на объект:

  • Используй Android Profiler для поиска в рабочем приложении
  • Добавь LeakCanary для автоматического обнаружения
  • Проверь Retain Path в Heap Dump
  • Избегай типичных утечек: контекст в синглтонах, listener без unsubscribe, static кэши