WeakHashMap 是 Java 中基于弱引用实现内存敏感缓存的工具,其 key 为弱引用、value 为强引用,GC 时 key 仅剩弱引用即被回收并自动清理条目;适用于短命、强关联对象缓存,禁用字符串字面量等常量作 key。

WeakHashMap 是 Java 中实现内存敏感缓存最直接、最常用的方式,它天然利用弱引用机制,在不增加额外清理逻辑的前提下,让缓存随对象生命周期自然消亡。
WeakHashMap 的缓存逻辑本质
它的键(key)是弱引用,值(value)是强引用。只要外部代码不再持有该 key 的强引用,下一次 GC 就会回收 key 对象,并在后续 map 操作中自动清理整个条目。
- 缓存项的“存活”完全绑定于 key 的强引用存在与否,不是靠时间或访问频次淘汰
- 适合缓存那些本就短暂、可重建、且与某个业务对象强关联的数据,比如:Activity 关联的 UI 配置、监听器附带的元数据、线程上下文快照
- 不适用于 key 是字符串字面量(如 "user_123")的场景——这类常量池对象永不回收,缓存条目也永远不会被清理
典型用法:避免手动管理生命周期
以缓存数组摘要为例,key 是原始数组对象本身,value 是计算开销较大的 Summary:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
private final WeakHashMap<int[], Summary> arraySummaryCache = new WeakHashMap<>();
Summary getSummary(int[] arr) {
if (arr == null) return null;
Summary cached = arraySummaryCache.get(arr);
if (cached != null) return cached;
cached = new Summary(arr);
arraySummaryCache.put(arr, cached); // arr 是 key → 弱引用
return cached;
}
- 只要调用方释放了对 同一数组实例 的强引用(如局部变量置为 null),该缓存条目就会在下次 GC 后自动失效
- 无需定时扫描、LRU 排序或手动 remove,清理由 WeakHashMap 内部的
expungeStaleEntries()在每次get/put/size等操作前自动触发 - 注意:value(Summary)仍是强引用,若它自身持有大对象或资源,需确保其设计为轻量、无泄漏
和软引用缓存的关键区别
WeakHashMap 不是“内存不足时才回收”,而是“GC 时发现 key 仅剩弱引用就立刻回收”。这决定了它的适用边界:
立即学习“Java免费学习笔记(深入)”;
- 适合短命、高耦合场景:比如一个临时解析器对象生成的中间结果,只服务于当前请求上下文
- 不适合通用高频缓存:因 GC 时机不可控,命中率波动大;若 key 频繁创建又丢弃,缓存可能几乎无效
- 若需要“尽量保留、仅在内存紧张时释放”,应选
SoftReference+ 自定义 Map,而非 WeakHashMap
使用时必须避开的坑
- 不要用 String 字面量、Integer 缓存值(-128~127)、枚举等常量对象作 key —— 它们不会被 GC,缓存永驻
- 避免 value 持有对 key 的反向强引用(比如 value 里存了 key 的引用或闭包),否则 key 永远无法回收,造成隐式内存泄漏
- WeakHashMap 的
size()返回的是当前有效条目数,但遍历时仍可能遇到已失效条目(内部 Entry 尚未完全清理),所以不建议直接 for-each 遍历做业务判断

















