java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java WeakReference用法

java引用类型WeakReference用法及原理详解

作者:看透也说透kevin

Java弱引用(WeakReference)是一种特殊的引用类型,当垃圾回收器运行时,无论内存是否充足,只要发现对象仅被弱引用指向,就会立即回收该对象,这篇文章主要介绍了java引用类型WeakReference用法及原理的相关资料,需要的朋友可以参考下

1. 核心概念:什么是 WeakReference?

WeakReference(弱引用)是 Java java.lang.ref 包下提供的一种引用类型。它的特点是:当垃圾回收器(GC)进行扫描时,无论当前内存是否充足,只要被弱引用关联的对象没有其他强引用**,那么这个对象就会被回收

这与我们平时普通的对象引用(强引用,Strong Reference)形成鲜明对比:

2. 工作原理

WeakReference 的工作原理与 Java 的垃圾回收机制紧密相关。JVM 中的垃圾回收器使用可达性分析算法来判断对象是否存活。

可达性分析:
GC Roots 是所有引用链的起点(如虚拟机栈中的局部变量、静态变量等)。如果一个对象到 GC Roots 没有任何引用链相连,则证明此对象是不可用的。

引用级别(强度从高到低):

  1. 强引用 (Strong Reference):绝不回收。
  2. 软引用 (Soft Reference):内存不足时(OOM 前)才回收。
  3. 弱引用 (Weak Reference)发现即回收。只要 GC 发现一个对象只被弱引用指向,就会立刻将其标记为可回收对象,并在下一次 GC 时回收其内存。
  4. 虚引用 (Phantom Reference):对象回收跟踪。无法通过它获取对象实例,其唯一目的是在对象被回收时收到一个系统通知。

WeakReference 的工作流程可以简化为:

  1. 你创建一个对象,并用一个 WeakReference 来包装它。
  2. 当你将对象的强引用置为 nullobj = null;)后,这个对象就只剩下 WeakReference 这一个“微弱”的引用了。
  3. 下一次垃圾回收发生时,GC 会发现这个对象是“弱可达”的。
  4. GC 会立即回收这个对象的内存
  5. 回收之后,你的 WeakReference.get() 方法将返回 null

3. 主要用法和示例

基本使用

import java.lang.ref.WeakReference;

public class WeakReferenceDemo {
    public static void main(String[] args) {
        // 1. 创建一个强引用对象
        Object strongRef = new Object();

        // 2. 用弱引用包装这个对象
        WeakReference<Object> weakRef = new WeakReference<>(strongRef);

        // 3. 此时既有强引用,也有弱引用。GC 不会回收它。
        System.out.println("Before GC (Strong ref exists): " + weakRef.get()); // 有输出

        // 4. 切断强引用!这是关键一步。
        strongRef = null;

        // 5. 建议系统进行垃圾回收(这只是建议,不保证立即执行)
        System.gc();

        // 6. 给 GC 一点时间执行
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 7. 检查弱引用指向的对象是否被回收
        System.out.println("After GC (Only weak ref): " + weakRef.get()); // 输出 null
    }
}

输出结果:

Before GC (Strong ref exists): java.lang.Object@1b6d3586
After GC (Only weak ref): null

典型应用场景:实现内存敏感的缓存

这是 WeakReference 最经典的使用场景。你可以用它来构建一个缓存,当内存不足时,缓存中的条目会被自动清除,从而避免内存泄漏(Memory Leak)。

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

public class SimpleCache<K, V> {
    private final Map<K, WeakReference<V>> cache = new HashMap<>();

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

    public V get(K key) {
        WeakReference<V> weakRef = cache.get(key);
        if (weakRef != null) {
            // 如果弱引用指向的对象还没被GC回收,就返回它
            return weakRef.get();
        }
        // 如果被回收了或者不存在,就返回null
        return null;
    }

    // 可以添加一个方法来清理Map中那些已经被GC回收的条目(key还在,value为null的Entry)
    public void cleanUp() {
        cache.entrySet().removeIf(entry -> entry.getValue().get() == null);
    }
}


为什么这样用?

缓存的数据通常不是至关重要的。如果内存紧张,丢弃部分缓存数据是可以接受的,应用程序可以从原始数据源(如数据库)重新加载。使用 WeakReference 可以让 GC 充当你的“缓存清理工”,自动管理内存,你无需编写复杂的内存淘汰算法(如 LRU)。

注意: 上面的 SimpleCache 中的 Map 本身仍然持有 key 的强引用和 WeakReference 对象的强引用。如果 key 本身是一个大对象,你可能需要类似 WeakHashMap 的结构。

4. 注意事项

  1. 配合 ReferenceQueue 使用:你可以将一个 ReferenceQueue 传递给 WeakReference 的构造函数。当弱引用指向的对象被垃圾回收后,这个 WeakReference 对象本身会被加入到这个队列中。这允许你执行一些后续的清理工作,例如从缓存 Map 中移除对应的键。

    ReferenceQueue queue = new ReferenceQueue<>();
    WeakReference weakRef = new WeakReference<>(new Object(), queue);
    // … 之后可以检查 queue.poll() 来获取被回收的引用

  2. 不是银弹WeakReference 主要用于缓解内存问题,而不是解决逻辑问题。你的代码必须能处理 get() 返回 null 的情况(即对象已被回收)。

  3. 性能:频繁创建 WeakReference 对象和进行 GC 本身也有开销,不要滥用。

  4. 与 SoftReference 的区别

    • WeakReference:GC 看到就回收,更激进。
    • SoftReference:只有在内存不足(即将发生 OOM)时才会回收,更适合做缓存,因为能尽可能长时间地保留数据。而 WeakReference 的缓存被回收得更快。

总结

特性描述
本质一种不影响垃圾回收决策的引用类型。
核心原则仅被弱引用关联的对象,在 GC 时必定被回收。
主要用途实现规范化映射(如 WeakHashMap)、内存敏感的高速缓存监听器列表等,防止因缓存等原因导致的内存泄漏。
如何使用1. 创建 WeakReference 包装对象。
2. 确保没有其他强引用指向该对象。
3. 在代码中总是检查 get() 是否返回 null

到此这篇关于java引用类型WeakReference用法及原理的文章就介绍到这了,更多相关java WeakReference用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文