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) 资源清理、监控对象生命周期
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐