Какие знаешь виды ссылок в JVM?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды ссылок в 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)
}
}