Java引用机制之强引用、软引用、弱引用和虚引用的实战指南

 更新时间:2025年12月12日 09:15:35   作者:拾荒的小海螺  
Java 的引用机制是垃圾回收(GC)体系中极为关键的一部分,不同引用类型代表不同的对象生命周期管理方式,Java 从 JDK 1.2 起提供了四种引用级别强引用、软引用、弱引用和虚引用,本文将逐一讲解它们的特点、内存行为、适用场景,并提供实践示例代码

1、简述

Java 的引用机制是垃圾回收(GC)体系中极为关键的一部分,不同引用类型代表不同的对象生命周期管理方式。合理使用引用类型,可以显著优化内存利用率,提高系统稳定性,尤其在缓存设计、资源管理和大规模数据处理场景中。

Java 从 JDK 1.2 起提供了四种引用级别:

  • 强引用(Strong Reference)
  • 软引用(Soft Reference)
  • 弱引用(Weak Reference)
  • 虚引用(Phantom Reference)

本文将逐一讲解它们的特点、内存行为、适用场景,并提供实践示例代码。

2、引用机制

2.1 强引用(Strong Reference)

特点

  • Java 默认的引用方式,例如:Object obj = new Object();
  • 最强引用级别,只要存在强引用,GC 永不会回收该对象。
  • 可能导致 OOM,如果强引用链无法断开。

典型应用

  • 普通对象的创建与访问。
  • 业务逻辑中绝大部分引用。

2.2 软引用(Soft Reference)

特点

  • 内存不足时,GC 会优先回收软引用指向的对象
  • 非内存不足时,不会被回收。
  • 适用于构建内存敏感缓存(如图片缓存、数据缓冲区等)。

典型应用

  • Guava Cache、部分本地缓存策略。
  • 内存有限的移动端、IoT 程序的资源管理。
import java.lang.ref.SoftReference;

public class SoftRefDemo {
    public static void main(String[] args) {
        SoftReference<byte[]> softRef = new SoftReference<>(new byte[10 * 1024 * 1024]); // 10MB
        System.out.println("Before GC: " + softRef.get());

        System.gc();
        System.out.println("After GC: " + softRef.get());  // 大概率存在

        // 占用大量内存触发回收
        try {
            byte[] bigData = new byte[100 * 1024 * 1024];
        } catch (Error e) {
            System.out.println("内存不足,软引用对象被回收: " + softRef.get());
        }
    }
}

2.3 弱引用(Weak Reference)

特点

  • 一旦 GC 执行,无论内存是否紧张,都会回收弱引用指向的对象。
  • 弱引用典型特点:朝生暮死

典型应用

  • 缓存(比软引用更“短命”)。
  • ThreadLocalMap 的 key(防止内存泄漏)。
  • 弱键 HashMap(WeakHashMap)。
import java.lang.ref.WeakReference;

public class WeakRefDemo {
    public static void main(String[] args) {
        WeakReference<String> weakRef = new WeakReference<>(new String("hello weak"));
        System.out.println("Before GC: " + weakRef.get());

        System.gc();
        System.out.println("After GC: " + weakRef.get());  // 必定为 null
    }
}

2.4 虚引用(Phantom Reference)

特点

  • 最弱的引用类型:phantomRef.get() 永远返回 null。
  • 必须结合 ReferenceQueue 使用。
  • GC 回收对象前,会将虚引用放入队列,用于资源清理。

应用场景

  • 替代 finalize(),实现更安全的资源释放。
  • 监控对象回收过程。
  • DirectByteBuffer 底层内存释放机制。
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomRefDemo {
    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        Object obj = new Object();
        PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue);

        System.out.println("Phantom get(): " + phantomRef.get()); // 永远是 null

        obj = null;
        System.gc();

        Thread.sleep(100);
        System.out.println("引用队列是否有元素: " + (queue.poll() != null));
    }
}

3、结合实际场景的应用示例

3.1 使用软引用构建简单缓存

import java.lang.ref.SoftReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SoftCache<K, V> {
    private final Map<K, SoftReference<V>> cache = new ConcurrentHashMap<>();

    public void put(K key, V value) {
        cache.put(key, new SoftReference<>(value));
    }

    public V get(K key) {
        SoftReference<V> ref = cache.get(key);
        return ref == null ? null : ref.get(); // 若被回收则返回 null
    }
}

3.2 WeakHashMap 自动回收 key

import java.util.WeakHashMap;

public class WeakHashMapDemo {
    public static void main(String[] args) {
        WeakHashMap<Object, String> map = new WeakHashMap<>();
        Object key = new Object();
        map.put(key, "value");

        System.out.println("Before: " + map);

        key = null;
        System.gc();

        try { Thread.sleep(100); } catch (Exception ignored) {}
        System.out.println("After: " + map);
    }
}

4、总结

  • 强引用:正常使用,生命周期最长
  • 软引用:适合可回收缓存,避免 OOM
  • 弱引用:适合避免内存泄漏,如 WeakHashMap、ThreadLocal
  • 虚引用:适用于对象回收监听,资源释放管理

掌握这四种引用方式,有助于在高性能、高并发系统中更精细地管理内存,提高系统健壮性。

引用类型GC 回收时机是否可通过 get() 获得对象常见用途
强引用永不回收可以普通对象
软引用内存不足时回收可以缓存(内存敏感)
弱引用一遇 GC 即回收可以WeakHashMap、避免内存泄漏
虚引用回收前通知不可以(always null)资源清理、监控对象生命周期

以上就是Java引用机制之强引用、软引用、弱引用和虚引用的实战指南的详细内容,更多关于Java强引用、软引用、弱引用和虚引用的资料请关注脚本之家其它相关文章!

相关文章

  • Java虚拟机如何运行Java字节码

    Java虚拟机如何运行Java字节码

    这篇文章主要介绍了Java虚拟机如何运行Java字节码的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • java异常中throw和throws的区别及说明

    java异常中throw和throws的区别及说明

    这篇文章主要介绍了java异常中throw和throws的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • MyBatis-Plus Page 分页不生效的问题解决

    MyBatis-Plus Page 分页不生效的问题解决

    分页是常见的一种功能,本文主要介绍了MyBatis-Plus Page分页不生效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-07-07
  • Springboot配置管理Externalized Configuration深入探究

    Springboot配置管理Externalized Configuration深入探究

    这篇文章主要介绍了Springboot配置管Externalized Configuration深入探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Spring源码解析后置处理器梳理总结

    Spring源码解析后置处理器梳理总结

    这篇文章主要介绍了Spring源码解析后置处理器梳理总结,在前面几篇文章中梳理了Spring中bean的创建过程,在这个过程中各式各样的后置处理器发挥了不同的作用,可以说后置处理器贯穿了bean的实例化以及初始化过程
    2022-07-07
  • java中对象和JSON格式的转换方法代码

    java中对象和JSON格式的转换方法代码

    JSON格式可以轻松地以面向对象的方式转换为Java对象,下面这篇文章主要给大家介绍了关于java中对象和JSON格式的转换方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • Spring(一):IOC如何推导和理解

    Spring(一):IOC如何推导和理解

    下面小编就为大家带来一篇详谈Spring对IOC的理解(推荐篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-07-07
  • Java语言Iterator转换成 List的方法

    Java语言Iterator转换成 List的方法

    在 Java 中,迭代器(Iterator)是一种用于遍历集合中元素的对象,它提供了一种简单而一致的方式来访问集合中的元素,而不需要暴露集合内部的结构,这篇文章主要介绍了Java语言Iterator转换成 List的方法,需要的朋友可以参考下
    2023-08-08
  • java解一个比较特殊的数组合并题

    java解一个比较特殊的数组合并题

    这篇文章主要介绍了java解一个比较特殊的数组合并题,需要的朋友可以参考下
    2014-06-06
  • Idea中springboot项目的热部署无法生效问题解决

    Idea中springboot项目的热部署无法生效问题解决

    本文主要介绍了Idea中springboot项目的热部署无法生效问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-10-10

最新评论