WeakHashMap通过弱引用key实现数组缓存的自动回收:以数组为key、附加信息为value,确保无强引用时GC可回收数组并清理条目;若将数组放value中则无法释放。
WeakHashMap 本身不直接缓存数组对象,而是缓存“对数组的弱引用”——更准确地说,它用弱引用作为
key
,从而在 key 所指向的对象(比如某个数组)不再被强引用时,允许该 key-value 对在下一次 GC 后自动从 map 中移除。因此,要实现“内存不足时可被自动回收的数组对象引用缓存”,关键不是把数组放 value 里就完事,而是让数组成为 key(或至少其生命周期由 WeakReference 控制),并配合合理的使用模式。
核心思路:用 WeakReference 包装数组作 key,或直接用数组作 key
WeakHashMap 的 key 是弱可达的:只要没有其他强引用指向该 key 对象,GC 就可能回收它,随后对应 entry 会在后续的 map 操作(如 get、put、resize)中被清理。所以最直接的方式是:
把数组对象本身作为 WeakHashMap 的 key(数组是 Object 子类,可作 key);
value 存放你真正想缓存的附加信息(比如计算结果、元数据、包装后的视图等);
确保
外部代码不长期持有该数组的强引用
——否则 GC 不会回收它,WeakHashMap 也就不会失效。
为什么不能把数组放在 value 里?
WeakHashMap 只对 key 使用弱引用,value 仍是强引用。如果你写成:
那么即使 "key" 字符串被回收(其实字符串常量池里一般不会),bigArray 仍被 value 强引用着,完全不会被释放。这违背了“内存敏感缓存”的初衷。
实用示例:缓存大数组的统计摘要
假设你频繁处理不同大 int[],每次都要算 sum/max/min,想缓存结果,但又不希望阻碍数组回收:
以数组对象为 key,摘要对象(如 Summary)为 value;
调用方需注意:处理完数组后,尽快释放对该数组的强引用(比如局部变量离开作用域、置 null);
WeakHashMap 内部会在 GC 后自动清理已不可达数组对应的条目。
进阶:需要 key 稳定且支持非数组对象?用 WeakReference 自定义 key
如果 key 需要复用(比如相同内容的不同数组实例应视为同一逻辑 key),就不能直接用数组对象。此时可封装一个弱引用 key:
自定义 key 类,内部持
和内容哈希(如 Arrays.hashCode(arr));
重写
基于数组内容而非引用;
但要注意:WeakReference#get() 可能返回 null,equals 中需做空检查;
这种方案更灵活,但也更复杂,且仍依赖外部不强持数组。
不复杂但容易忽略:WeakHashMap 的清理是惰性的,依赖后续 map 操作触发 cleanup。若长时间只 put 不 get/size/entrySet,残留的 stale entry 可能暂时占用内存。必要时可手动调用
(仅调试)或定期执行
触发清理。
cache.put("key", bigArray);private final WeakHashMap 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;
} WeakReferenceequals/hashCodeSystem.gc()cache.size()