WeakHashMap 的 key 能被 GC 回收是因为其 Entry 继承 WeakReference,JVM GC 时自动清理仅被弱引用指向的 key;value 非弱引用,若 value 强引用 key 会导致内存泄漏。

WeakHashMap 的 key 为什么能被 GC 回收
关键在 WeakReference:WeakHashMap 的 key 被包装成 WeakReference 存入内部的 Entry(继承自 WeakReference),而 JVM 在每次 GC 时会自动清空仅被弱引用指向的对象。只要外部不再持有该 key 的强引用,下一次 GC 后,对应 entry 就可能从 map 中消失。
注意:value 不是弱引用——如果 value 又反过来强引用了 key(比如 value 是一个持有 key 引用的内部类实例),就会形成“key → value → key”闭环,导致 key 实际无法被回收,这就是典型的泄漏场景。
WeakHashMap 不适合当普通缓存用
它不是为缓存设计的,而是为“生命周期依附于 key”的映射关系服务的,比如:
- 监听器注册表(key 是监听对象,监听器销毁后自动清理)
- 代理类与原始对象的绑定(key 是原始对象,避免阻止其回收)
常见误用:WeakHashMap 存缓存——String 字面量或常量池中的字符串永远不会被 GC,entry 永远不会清除;用 new String("xxx") 又违背缓存本意,且仍可能因其他强引用残留。
立即学习“Java免费学习笔记(深入)”;
WeakHashMap 的 size() 和迭代器行为不稳定
因为 GC 是异步触发的,size() 返回的只是当前未被清理的 entry 数量,不代表“逻辑上还有效的条目数”。更危险的是遍历时:
- 迭代过程中发生 GC,某些 entry 可能在 next() 调用前就被清除,导致
ConcurrentModificationException或跳过元素 -
entrySet().iterator()不保证线程安全,也不保证遍历完整性
实操建议:不要依赖 size() 做业务判断;如需稳定遍历,先 new ArrayList(map.entrySet()) 快照,但注意这会暂时延长 value 的存活时间。
替代 WeakHashMap 的现代方案
JDK 1.8+ 更推荐用 java.lang.ref.Cleaner 或 PhantomReference 配合显式清理逻辑;对于缓存场景,应优先考虑 caffeine 或 guava Cache,它们支持弱键/弱值、软引用、LRU、过期等策略,并规避了 WeakHashMap 的语义陷阱。
WeakHashMap 真正不可替代的点只有一个:你需要「key 被回收时,map 自动失效该映射」,且不希望额外维护清理线程或注册回调——但这个需求本身就很窄,多数时候是设计信号:该换数据结构了。









