本文目录导读:

- 案例1:
WeakHashMap——自动清理的缓存 - 案例2:
WeakReference+ReferenceQueue——对象回收监听 - 案例3:Android 中的
AsyncDrawable使用弱引用避免内存泄漏 - 案例4:自定义弱引用缓存(适合内存敏感场景)
在Java中,弱引用(WeakReference)最常见的应用场景是缓存和避免内存泄漏,下面通过几个经典案例来说明。
案例1:WeakHashMap——自动清理的缓存
这是最经典的弱引用应用。WeakHashMap 的键使用弱引用,当键对象不再被外部强引用时,GC 会自动回收键,对应的键值对也会被自动移除。
import java.util.WeakHashMap;
import java.util.Map;
public class WeakHashMapDemo {
public static void main(String[] args) {
Map<Object, String> cache = new WeakHashMap<>();
// 创建一个键对象
Object key = new Object();
cache.put(key, "some data");
System.out.println("Before GC: " + cache.size()); // 1
// 取消强引用
key = null;
// 触发 GC
System.gc();
// 等待 GC 完成(建议等待一小段时间)
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("After GC: " + cache.size()); // 0(已被自动清理)
}
}
输出(取决于 JVM 和 GC 时机,但通常类似):
Before GC: 1
After GC: 0
核心思想:当外部不再强引用 key 时,WeakHashMap 中的条目自动消失,避免了缓存无限膨胀。
案例2:WeakReference + ReferenceQueue——对象回收监听
这个案例展示了如何监控对象被 GC 回收的时刻,常用于资源清理或对象生命周期追踪。
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
class HeavyResource {
// 模拟占用大量内存的资源
private byte[] data = new byte[10 * 1024 * 1024]; // 10MB
}
public class WeakReferenceWithQueueDemo {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<HeavyResource> queue = new ReferenceQueue<>();
HeavyResource resource = new HeavyResource();
WeakReference<HeavyResource> weakRef = new WeakReference<>(resource, queue);
System.out.println("Before GC: " + weakRef.get()); // 非空
// 取消强引用
resource = null;
// 触发 GC
System.gc();
// 检查队列,看对象是否已被回收
System.out.println("Reference queued: " + (queue.poll() != null)); // true(可能延迟)
Thread.sleep(100);
System.out.println("After GC: " + weakRef.get()); // null(已被回收)
}
}
输出:
Before GC: HeavyResource@...
Reference queued: true
After GC: null
核心思想:通过 ReferenceQueue 得知对象何时被回收,可用于执行后续清理或通知。
案例3:Android 中的 AsyncDrawable 使用弱引用避免内存泄漏
这是 Android 开发中的经典实践,当异步任务持有 Activity 或 View 的引用时,很容易造成内存泄漏,使用弱引用可以避免。
public class ImageLoader {
// 回调接口,内部使用弱引用持有宿主
public static class LoadCallback extends WeakReference<ImageView> {
public LoadCallback(ImageView imageView) {
super(imageView);
}
public void onLoadSuccess(Bitmap bitmap) {
ImageView imageView = get(); // 获取弱引用的对象
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
// imageView 已被销毁(get 返回 null),则什么都不做
}
}
public void loadImage(String url, ImageView imageView) {
LoadCallback callback = new LoadCallback(imageView);
// 异步加载图片...
// 加载完成后调用 callback.onLoadSuccess(bitmap)
}
}
核心思想:LoadCallback 并不强持有 ImageView,当 Activity 被销毁时,ImageView 不再被强引用,GC 可以回收它,即使异步任务还在后台运行,也不会阻止 ImageView 的内存释放,从而避免泄漏。
案例4:自定义弱引用缓存(适合内存敏感场景)
如果希望自己实现一个缓存,当内存紧张时自动释放部分数据,可以使用 WeakReference 包装值对象。
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
public class WeakValueCache<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> ref = cache.get(key);
if (ref == null) {
return null;
}
V value = ref.get();
if (value == null) {
// 已被 GC 回收,从缓存中移除
cache.remove(key);
}
return value;
}
}
使用示例:
WeakValueCache<String, Object> cache = new WeakValueCache<>(); String key = "id_123"; Object data = new Object(); cache.put(key, data); // data 还被强引用,可以获取到 System.out.println(cache.get(key)); // 非空 data = null; // 取消强引用 System.gc(); // 此时缓存可能已被 GC 清理 System.out.println(cache.get(key)); // 可能为 null
| 案例 | 使用方式 | 解决什么问题 |
|---|---|---|
WeakHashMap |
键使用弱引用 | 缓存自动清理,防止内存泄漏 |
WeakReference + ReferenceQueue |
对象引用 + 回收监听 | 跟踪对象生命周期,触发清理操作 |
Android AsyncDrawable |
回调中弱引用宿主 | 避免异步任务导致 Activity 泄漏 |
| 自定义弱引用缓存 | 值使用弱引用 | 内存敏感场景下的自动释放 |
核心结论:弱引用的本质是“允许对象在没有强引用时被 GC 回收”,常用于缓存、观察者模式、回调等场景,防止内存泄漏。