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

Какие знаешь виды ссылок в JVM?

2.8 Senior🔥 111 комментариев
#JVM и память#Производительность и оптимизация

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Виды ссылок в JVM

В JVM существует 4 основных типа ссылок на объекты. Каждый тип определяет, как сборщик мусора (Garbage Collector) будет обращаться с объектом при нехватке памяти.

1. Strong References (Сильные ссылки)

Strong reference — это обычная ссылка, с которой работаешь ежедневно.

val user = User("John")  // Сильная ссылка
val anotherRef = user     // Ещё одна сильная ссылка

Объект User остаётся в памяти, пока существует хотя бы одна strong reference на него. GC удалит объект только после того, как все strong references будут удалены.

Минус: может привести к утечкам памяти, если случайно держишь ссылку на неживой объект.

2. Weak References (Слабые ссылки)

Weak reference — это ссылка, которая не препятствует GC удалить объект.

import java.lang.ref.WeakReference

var user: User? = User("John")
val weakRef = WeakReference(user)

user = null  // Удалили strong reference

// GC может удалить User прямо сейчас
val retrievedUser = weakRef.get()  // Может быть null!
if (retrievedUser != null) {
    println(retrievedUser.name)
} else {
    println("Объект был удалён сборщиком мусора")
}

Использование:

  • Кэши, которые могут быть пересчитаны
  • WeakHashMap в Java (удаляет записи, если ключ удалён GC)
  • Слушатели событий, чтобы избежать утечек памяти

3. Soft References (Мягкие ссылки)

Soft reference — это ссылка, которая позволяет GC удалить объект только если памяти критически не хватает.

import java.lang.ref.SoftReference

var user: User? = User("John")
val softRef = SoftReference(user)

user = null  // Удалили strong reference

// Если памяти достаточно, объект останется в памяти
// Если памяти не хватает, GC удалит объект
val retrievedUser = softRef.get()  // Может быть null при нехватке памяти

Использование:

  • Кэши изображений в памяти
  • Кэширование веб-контента
  • Данные, которые можно пересчитать, но дорого пересчитывать

4. Phantom References (Фантомные ссылки)

Phantom reference — это ссылка, которая позволяет отследить, когда объект был удалён GC. Она всегда возвращает null при вызове get().

import java.lang.ref.PhantomReference
import java.lang.ref.ReferenceQueue

val queue = ReferenceQueue<User>()
val user: User? = User("John")
val phantomRef = PhantomReference(user, queue)

// phantomRef.get() ВСЕГДА вернёт null
println(phantomRef.get())  // null

// Используется с ReferenceQueue для отслеживания удаления
// Когда объект будет удалён, phantomRef попадёт в queue

Использование:

  • Очистка ресурсов (like try-with-resources)
  • Отслеживание удаления объектов для логирования/отладки
  • Системное администрирование памяти
  • Finalizers более безопасная альтернатива

Сравнительная таблица

ТипGC удалит когдаget() вернётИспользование
StrongНет strong refsОбъектОбычные ссылки
WeakВсегда можетnull если GC удалилКэши, Listeners
SoftПри нехватке памятиnull если память критичнаБольшие кэши
PhantomКак weak (но с очередью)Всегда nullОчистка ресурсов

Практический пример: Утечка памяти

class ActivityListener(val activity: Activity) {
    fun onEvent() {
        println(activity.toString())
    }
}

// BAD — утечка памяти
class EventManager {
    private val listeners = mutableListOf<ActivityListener>()
    
    fun register(listener: ActivityListener) {
        listeners.add(listener)  // Strong reference
    }
}

// GOOD — используем WeakReference
class EventManager {
    private val listeners = mutableListOf<WeakReference<ActivityListener>>()
    
    fun register(listener: ActivityListener) {
        listeners.add(WeakReference(listener))
    }
    
    fun notifyListeners() {
        listeners.removeAll { it.get() == null }  // Очистка мёртвых ссылок
        listeners.forEach { it.get()?.onEvent() }
    }
}

Практический пример: WeakHashMap

// WeakHashMap удаляет записи, если ключ был удалён GC
val cache = WeakHashMap<String, ByteArray>()

var key: String? = "image_key"
cache[key] = ByteArray(1024 * 1024)  // 1 MB

key = null  // Удалили ссылку на ключ
// GC может удалить ключ, и запись автоматически исчезнет из cache

Важные правила

  • Strong references — используй по умолчанию
  • Weak references — для кэшей и listeners, чтобы избежать утечек
  • Soft references — для больших кэшей (изображения, HTML)
  • Phantom references — редко, в основном для системного кода
  • Android Activity: всегда используй WeakReference если передаёшь Activity в другие объекты

Частая ошибка в Android

// BAD — утечка памяти при повороте экрана
class MyActivity : AppCompatActivity() {
    companion object {
        var activity: MyActivity? = null  // Strong reference в companion object!
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        activity = this  // Activity останется в памяти навсегда
    }
}

// GOOD
class MyActivity : AppCompatActivity() {
    companion object {
        var activity: WeakReference<MyActivity>? = null
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        activity = WeakReference(this)
    }
}