本文目录导读:

WeakHashMap弱键自动回收机制
WeakHashMap 是 Java 中的一种特殊 Map 实现,其键使用弱引用(WeakReference)包装,当键对象不再被外部强引用持有时,垃圾回收器会自动回收该键,并自动删除对应的条目。
核心原理
// 简化的内部实现
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;
}
自动回收触发条件
键对象失去强引用
public class WeakHashMapDemo {
public static void main(String[] args) {
WeakHashMap<KeyObject, String> map = new WeakHashMap<>();
// 创建强引用
KeyObject key = new KeyObject("key1");
map.put(key, "value1");
// key仍然有强引用,不会回收
System.out.println(map.size()); // 1
key = null; // 移除强引用
// 此时只有 WeakHashMap 中的弱引用持有该键
// GC 后会被回收
System.gc();
System.out.println(map.size()); // 0(可能为0)
}
}
GC 执行时自动清理
当垃圾回收器运行时,会通过 ReferenceQueue 机制检测弱引用是否被回收:
// WeakHashMap 内部的 ReferenceQueue
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
// 清理方法,在每次操作时调用
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length);
// 从哈希表中移除该条目
// ...
}
}
}
实际应用场景
缓存系统
public class ImageCache {
private WeakHashMap<ImageKey, BufferedImage> cache = new WeakHashMap<>();
public BufferedImage getImage(ImageKey key) {
BufferedImage img = cache.get(key);
if (img == null) {
img = loadFromDisk(key);
cache.put(key, img);
}
return img;
}
}
元数据存储
public class MetadataManager {
private WeakHashMap<Object, Metadata> metadataMap = new WeakHashMap<>();
public void setMetadata(Object obj, Metadata meta) {
metadataMap.put(obj, meta);
}
public Metadata getMetadata(Object obj) {
return metadataMap.get(obj);
}
// 当对象不再使用时,元数据自动清理
}
监听器/回调注册
public class EventManager {
private WeakHashMap<Listener, Void> listeners = new WeakHashMap<>();
public void register(Listener listener) {
listeners.put(listener, null);
}
// 监听器对象不再使用时自动移除,避免内存泄漏
}
关键注意事项
值对象不会自动回收
WeakHashMap<Key, HeavyObject> map = new WeakHashMap<>(); map.put(key, new HeavyObject()); // 即使key被回收,value不会被回收! // 解决办法:值也使用弱引用包装 WeakHashMap<Key, WeakReference<HeavyObject>> safeMap = new WeakHashMap<>();
String 作为键的特殊情况
// String.intern() 返回的字符串有强引用
String s1 = "abc"; // 字符串常量池中的强引用
String s2 = new String("abc"); // 堆上的对象
map.put(s2, "value"); // s2可以被回收
map.put(s1, "value"); // 不可被回收
自动回收的时机不确定
// 不要依赖立即回收 map.put(key, "value"); key = null; System.gc(); // 此时可能尚未回收 Thread.sleep(100); // 建议调用 size() 等方法触发清理 map.size(); // 内部会调用 expungeStaleEntries()
与普通 HashMap 对比
| 特性 | WeakHashMap | HashMap |
|---|---|---|
| 键引用类型 | 弱引用 | 强引用 |
| 自动回收 | 支持 | 不支持 |
| 内存泄漏风险 | 低 | 高(需手动移除) |
| 使用场景 | 缓存、元数据 | 大多数场景 |
最佳实践
- 键必须是长生命周期的对象,否则很快会被回收
- 避免在并发场景下使用(非线程安全)
- 不适合存储短暂使用的键值对
- 结合 ReferenceQueue 使用可以监听回收事件
// 监听回收事件示例
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakHashMap<Object, String> map = new WeakHashMap<>();
// 可以另起线程监控回收
new Thread(() -> {
try {
while (true) {
Reference<? extends Object> ref = queue.remove();
System.out.println("键被回收: " + ref);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
WeakHashMap 的弱键自动回收机制在需要自动清理不用的条目时非常有用,特别适合缓存、元数据管理、监听器注册等场景,但需要理解其工作原理和限制,避免误用导致的问题。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播