WeakHashMap能避免内存泄漏,因其键为弱引用,无强引用时GC可回收键并自动移除条目;而HashMap的强引用会阻止GC,导致对象长期驻留内存。

WeakHashMap 适合做轻量级缓存,因为它的键是弱引用的——只要没有强引用指向该键,垃圾回收器就能在下一次 GC 时回收它,同时 WeakHashMap 会自动移除对应的键值对。
为什么 WeakHashMap 能避免内存泄漏
普通 HashMap 的键是强引用,即使业务逻辑已不再需要某个键对象,只要它还在 Map 中,GC 就不会回收它。WeakHashMap 把键包装成 WeakReference,JVM 在 GC 时会清空所有仅被弱引用持有的键对象,并在后续访问(如 get、put)时触发清理过期条目(通过 expungeStaleEntries())。
注意:WeakHashMap 的值仍是强引用。如果值也持有对键的强引用(比如值是一个包含 key 字段的对象),就会形成循环引用,导致键无法被回收——这是常见陷阱。
构建缓存的基本写法
直接使用 WeakHashMap 即可,但需注意以下几点:
- 键类型必须正确重写
equals()和hashCode(),否则弱引用失效后可能残留脏数据 - 不要用可变对象作键(如 ArrayList、StringBuilder),因为哈希值变化会导致 get 失败
- 不建议直接暴露 WeakHashMap 实例,应封装为线程安全的缓存类(尤其在多线程场景)
简单线程安全封装示例
若并发不高,可用 Collections.synchronizedMap 包装;若要求更高性能,可用 ConcurrentHashMap + 手动管理弱键逻辑(但注意 ConcurrentHashMap 不支持弱键,需自行结合 ReferenceQueue 实现)。更实用的做法是:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 用 WeakHashMap 存储键值对
- 读写操作加同步块(或使用 ReentrantLock)
- 定期调用
cleanUp()(内部触发 expungeStaleEntries)或在每次 get/put 后清理
例如:
private final Mappublic synchronized Value get(Key key) {
return cache.get(key);
}
public synchronized void put(Key key, Value value) {
cache.put(key, value);
}
适用场景与局限性
WeakHashMap 缓存适用于:
– 键对象生命周期由外部控制(如 UI 组件、数据库连接、临时上下文对象)
– 缓存命中率不高,且允许随时丢失条目
– 对内存敏感,不能容忍“缓存常驻”导致 OOM
不适合:
– 需要精确控制缓存大小或过期时间(WeakHashMap 没有 LRU、TTL 等机制)
– 键对象本身是常量或静态对象(如 String 字面量、Integer 小值),它们被 JVM 缓存,永不回收
– 值对象很大且与键强关联(此时应考虑软引用或手动解耦)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










