Backend

四种引用

四种引用

Java

强引用 (Strong Reference)

  • 最常见的引用类型。在 Java 中,默认情况下,任何普通的对象引用都是强引用。
  • 只要一个对象有强引用指向它,垃圾回收器永远不会回收该对象,即使系统内存紧张,宁愿抛出 OutOfMemoryError ,强引用对象也不会被清除。

软引用 (Soft Reference)

  • 软引用是用来描述一些还有用但并非必需的对象。
  • 当系统内存不足时,垃圾回收器会回收软引用指向的对象,避免内存溢出。在内存充足时,这些对象不会被回收。
  • 软引用通常用于实现缓存机制,允许程序在不影响性能的情况下利用多余内存。

软引用适合用于内存敏感的缓存场景。主要优势在于能够根据系统内存情况灵活地释放对象,适用于那些可以重建但需要较大内存的对象。例如,浏览器的图片缓存、文档处理程序的页面缓存等。

弱引用 (Weak Reference)

  • 弱引用是比软引用更弱的一种引用类型。
  • 只要垃圾回收器发现只有弱引用指向某个对象,该对象会立即被回收,无论系统内存是否充足。
  • 弱引用常用于防止内存泄漏,典型应用是 WeakHashMap,其中键是弱引用,当键不再被其他强引用持有时,键值对会被自动移除。它的优势在于避免对象长时间占用内存,适合短命对象或者临时缓存数据

虚引用 (Phantom Reference)

  • 虚引用是最弱的一种引用类型。
  • 虚引用对对象的生存时间没有任何影响。如果一个对象仅有虚引用,那么它与没有引用一样,随时会被垃圾回收。
  • 虚引用的主要作用是跟踪对象的垃圾回收状态。在对象被回收时,虚引用会被放入一个 ReferenceQueue,我们可以通过这个队列来执行一些清理或其他后续操作。

虚引用的唯一作用就是配合引用队列来监控引用的对象是否被加入到引用队列中,也就是可以准确的让我们知晓对象何时被回收。

为什么需要知晓对象何时被回收?为什么要去关心已经被gc了的对象呢?

原因在于jvm的gc只能回收java堆上的对象,不能够回收java堆外的资源或操作系统资源。

如果只是普通的对象,那么清理之后确实不需要额外的处理,也用不上虚引用。而还有一些对象持有非堆区的资源,如堆外资源,native资源等等,比如:

资源类型是否由 GC 自动释放
文件句柄/FileInputStream❌ 不释放,需要手动 close()
Socket / Network Connection❌ 不释放,需要手动 close()
DirectByteBuffer / 堆外内存❌ 不立即释放,需要调用 Cleaner 或自己释放
数据库连接❌ 不释放,需要 close()

这些资源jvm无法回收,此时就需要使用虚引用,但这些对象被gc回收时,通过轮训ReferenceQueue知道被回收的对象的是哪一个,然后来处理释放堆外资源

虚引用真正的用途是:

  1. 对象已经被 GC 判定可回收
  2. 但是对象持有的外部资源需要手动清理
  3. 通过 ReferenceQueue 通知你,让你在对象消亡后释放资源

换句话说,虚引用解决的问题是:对象的生命周期结束时,堆外资源怎么安全清理

post.comments