惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
Recent Announcements
Recent Announcements
有赞技术团队
有赞技术团队
The GitHub Blog
The GitHub Blog
N
Netflix TechBlog - Medium
腾讯CDC
A
About on SuperTechFans
博客园 - 叶小钗
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
D
DataBreaches.Net
D
Docker
宝玉的分享
宝玉的分享
量子位
Microsoft Azure Blog
Microsoft Azure Blog
Martin Fowler
Martin Fowler
博客园 - 三生石上(FineUI控件)
Jina AI
Jina AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
V2EX
Last Week in AI
Last Week in AI
H
Help Net Security
Hugging Face - Blog
Hugging Face - Blog
M
MIT News - Artificial intelligence

博客园 - 野鹤闲人

ubantu 耳机调试 keepalived+nginx msg广播到同一个group中,怎么保证所有consumer都消费到,Rocketmq和rabbitmq 分别是怎么做的 mysql优化语句时,关注哪几列 extra要关注吗 CountDownLatch/CyclicBarrier 区别 机器缩容要注意哪些问题 IO模型有哪几种 ConcurrentSkipListMap 并发安全实现 TreeMap hive 小文件优化 redis缓存雪崩问题解决 CAS原理 docker的常用命令 k8s的常用组件,和命令 mysql B+树 如果有3层,能保存多少数据 如何保证rabbitmq或kafka 消息不丢失,从生产到消费端全过程 java排查工具 git Spring 事务失效
JAVA 强软弱虚引用
野鹤闲人 · 2025-12-25 · via 博客园 - 野鹤闲人

在 Java 中,引用(Reference) 是对象与内存之间的关联方式,JDK 1.2 后将引用分为 强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference) 四类,核心目的是灵活控制对象的垃圾回收(GC)行为,适配不同的内存使用场景。

日常开发中最常用的引用方式,只要对象被强引用关联,JVM 就不会回收该对象,即使内存耗尽抛出 OutOfMemoryError,也不会主动回收强引用对象。

// 强引用:obj 是指向 Object 对象的强引用
Object obj = new Object(); 
  • 强引用是 Java 默认的引用类型,无需显式使用 java.lang.ref 包的类;
  • 即使对象暂时不用,只要有强引用,GC 就不会回收,可能导致内存泄漏(如静态集合持有大量无用对象的强引用);
  • 示例:List<Object> list = new ArrayList<>(); list.add(new Object()); 只要 list 不被清空 / 置空,其中的 Object 就不会被回收。

通过 java.lang.ref.SoftReference 类实现,是「内存敏感」的引用:

  • 当 JVM 内存充足时,软引用对象不会被回收;
  • 当 JVM 内存不足(即将触发 OOM)时,会优先回收所有软引用关联的对象;
  • 若回收软引用对象后仍内存不足,才会抛出 OutOfMemoryError
import java.lang.ref.SoftReference;

public class SoftReferenceDemo {
    public static void main(String[] args) {
        
  • 软引用常与 ReferenceQueue 配合:当软引用对象被 GC 回收后,软引用本身会被加入 ReferenceQueue,便于后续清理;
  • 核心场景:缓存(如手机 App 的图片缓存),既利用缓存提升性能,又能在内存不足时自动释放,避免 OOM。

通过 java.lang.ref.WeakReference 类实现,比软引用更「弱」:

  • 无论内存是否充足,只要 GC 扫描到仅被弱引用关联的对象,就会立即回收;
  • 弱引用的生命周期仅到下一次 GC 执行前。
import java.lang.ref.WeakReference;

public class WeakReferenceDemo {
    public static void main(String[] args) {
        
  • WeakHashMap:键(Key)是弱引用类型,当键的强引用断开后,GC 会回收键值对,避免内存泄漏;
  • ThreadLocal:内部通过 ThreadLocalMap 存储数据,ThreadLocalMap 的键是弱引用的 ThreadLocal 对象,防止 ThreadLocal 长期持有导致内存泄漏;
  • 临时数据存储:如配置项的临时缓存,无需长期保留,GC 时自动清理。

通过 java.lang.ref.PhantomReference 类实现,是最弱的引用类型,无法通过虚引用获取对象本身(get() 方法永远返回 null),仅用于「跟踪对象被 GC 回收的事件」。

  • 必须与 ReferenceQueue 配合使用:当虚引用关联的对象被 GC 回收时,虚引用会被加入 ReferenceQueue,程序通过监听 ReferenceQueue 感知对象已回收;
  • 虚引用的唯一目的:在对象被回收时执行一些清理操作(如释放堆外内存、关闭文件句柄等),弥补 Java 析构函数(finalize())的不足。
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomReferenceDemo {
    public static void main(String[] args) throws InterruptedException {
        
  • 堆外内存释放:Java NIO 的 DirectByteBuffer 会占用堆外内存,虚引用可跟踪其回收,确保堆外内存被及时释放;
  • 替代 finalize()finalize() 执行时机不可控,且可能导致对象复活,虚引用是更可靠的对象回收回调方式。
  1. 回收优先级:强引用 > 软引用 > 弱引用 > 虚引用(GC 优先回收虚引用对象,最后回收强引用对象);
  2. 使用方式:
    • 强引用:直接赋值(Object obj = new Object());
    • 软 / 弱 / 虚引用:需通过 java.lang.ref 包的对应类包装,其中虚引用必须配合 ReferenceQueue
  3. 核心设计目标:
    • 强引用:保证对象的正常使用,不被 GC 回收;
    • 软引用:内存友好的缓存,避免 OOM;
    • 弱引用:自动清理非必需对象,减少内存泄漏;
    • 虚引用:感知对象回收,处理堆外资源。
  • 误区 1:System.gc() 一定会触发 GC? ❌ 纠正:System.gc() 只是向 JVM 发送 GC 建议,JVM 可忽略(如新生代内存充足时),因此弱 / 软引用的回收时机不可精确控制;
  • 误区 2:弱引用对象被回收后,弱引用本身会自动失效? ❌ 纠正:弱引用对象被回收后,弱引用本身不会消失,需通过 ReferenceQueue 手动清理,否则会导致 Reference 对象堆积;
  • 误区 3:虚引用能获取对象? ❌ 纠正:虚引用的 get() 方法永远返回 null,仅能通过 ReferenceQueue 感知对象回收。