Java四种引用有哪些区别,给定场景下如何选择引用并说明策略?

1 个回答

  • 纪修竹
    人总要要沉下心来过一段宁静而自省的日子来整理自己。
    ## 作用 Java 的四种引用强度依次减弱,用于控制对象的生命周期以及垃圾回收时机: | 引用类型 | 对应类 | GC 行为 | 适用场景 | | --- | --- | --- | --- | | 强引用 | 默认引用 | 只要引用链可达,就不会回收 | 普通业务对象、必须长期使用的对象 | | 软引用 | `SoftReference` | 内存不足、即将发生 OOM 前回收 | 内存敏感型缓存,如图片缓存 | | 弱引用 | `WeakReference` | 只要发生 GC,就可能被回收 | `WeakHashMap`、规范化映射、临时缓存 | | 虚引用 | `PhantomReference` | 对象随时可能被回收,`get()` 通常返回 `null` | 跟踪对象回收、执行资源清理 | ## 原理与选择策略 ### 1. 强引用 - Java 中最常见、默认的引用方式,例如: ```java Object obj = new Object(); ``` - 只要强引用存在且引用链可达,垃圾收集器就不会回收该对象。 - 对象只有在以下情况下才可被回收: - 引用被显式设置为 `null`; - 引用超出作用域; - 引用链变为不可达。 - 如果静态集合、长生命周期对象持续持有不再使用的对象,会造成内存泄漏。 - **选择策略:** - 业务运行期间必须使用、不能丢失的对象使用强引用。 - 对象不再使用后,要及时从集合中移除或将引用置空。 ### 2. 软引用 - 使用 `SoftReference` 包装对象。 - 内存充足时,软引用对象通常不会被回收;当内存不足、JVM 即将抛出 `OutOfMemoryError` 前,垃圾收集器会尝试回收软引用对象。 - 软引用通常会记录对象的最后访问时间,JVM 可结合访问情况进行回收,文章中提到可按类似 LRU 的策略处理。 - **选择策略:** - 适合实现“有用但非必需”的缓存。 - 当缓存对象丢失后可以重新从磁盘、数据库或网络加载时,可以使用软引用。 - 使用时需要先调用 `get()`,如果返回 `null`,说明对象已被回收,需要重新创建或加载。 示例策略: ```java SoftReference<BufferedImage> ref = new SoftReference<>(image); BufferedImage cached = ref.get(); if (cached == null) { // 内存不足时已被回收,重新加载 } ``` ### 3. 弱引用 - 使用 `WeakReference` 包装对象。 - 弱引用对象的生命周期更短,无论当前内存是否充足,只要发生垃圾回收,就可能被回收。 - `WeakHashMap` 的 key 使用弱引用持有:当 key 不再被外部强引用引用后,下一次 GC 时该 Entry 就可能被清理。 - **选择策略:** - 适合对象只应在外部仍在使用时保留的场景。 - 可用于临时缓存、规范化映射,避免缓存本身阻止对象被回收。 - 不适合保存重建成本高且希望尽量保留的缓存,因为它会在下一次 GC 时失效。 ### 4. 虚引用 - 使用 `PhantomReference`,引用强度最弱。 - 对象是否可以被虚引用持有,不影响其回收;其 `get()` 方法通常总是返回 `null`,因此不能通过虚引用获取实际对象。 - 虚引用通常需要配合 `ReferenceQueue` 使用。 - 当对象被回收时,虚引用会被加入引用队列,程序可据此感知对象已经被回收,并执行一些清理操作。 - **选择策略:** - 不用于普通业务访问,也不用于常规缓存。 - 适合跟踪对象销毁过程、管理堆外内存或执行比 `finalize` 更可控的资源清理。 ## 场景选择总结 - **对象必须一直可用:** 使用强引用。 - **希望缓存尽量保留,但内存紧张时允许释放:** 使用软引用。 - **对象生命周期应由外部强引用决定,缓存不能阻止回收:** 使用弱引用。 - **只需要在对象被回收后得到通知并清理资源:** 使用虚引用。 使用软引用、弱引用或虚引用时,都应在访问对象前判断 `get()` 是否为 `null`;对象被回收后,需要执行重新加载、移除失效 Entry 或资源清理等逻辑。
    发布于 2026-10-27 22:33 •IP属地 西藏
    举报
    评论
    收藏