Map 的键是引用类型时,如何防止内存泄漏?
参考答案:
当 Map 的键是引用类型(如对象、数组、函数)时,如果不小心管理,会导致内存泄漏,因为:
Map对键是强引用,只要该键存在于Map中,它就不会被垃圾回收;- 即使代码中不再显式使用这个对象,只要它还在
Map里,它的内存就无法释放。
一、问题举例
js
const map = new Map();
function cacheUser(user) {
map.set(user, computeHeavyStuff(user));
}
// 某个 user 对象,即使业务中已经不再用它,但 map 中还持有它
// → user 永远不会被 GC 回收,内存常驻这在需要缓存大量对象时尤为危险,比如响应缓存、页面数据缓存等场景中,可能在用户无感知的情况下持续增加内存占用。
二、解决方案:使用 WeakMap
1. 什么是 WeakMap
WeakMap 是专为解决上述问题设计的数据结构:
- 它的键只能是对象(引用类型);
- 对键是弱引用,不阻止垃圾回收;
- 如果没有其他强引用指向某个键对象,它会被 GC 回收,
WeakMap也会自动清理对应的键值对。
2. 示例替换
js
const cache = new WeakMap();
function cacheUser(user) {
if (!cache.has(user)) {
cache.set(user, computeHeavyStuff(user));
}
return cache.get(user);
}当外部不再引用 user,这个对象就会被回收,WeakMap 不会阻止 GC。
三、WeakMap 的使用限制
- 无法遍历(没有
.keys()、.values()、.entries()); - 不能清空(没有
.clear()方法); - 无法观察删除(不会触发事件);
- 键必须是对象,不能是原始值。
这些限制是设计上的权衡,为的是让它成为GC 友好的结构,不干扰垃圾回收算法。
四、何时用 WeakMap 替代 Map
适用场景:
- 键为对象;
- 不需要枚举所有键;
- 缓存、映射、私有字段存储等用途;
- 期望自动释放内存的临时结构。
不适用:
- 需要遍历所有键值;
- 键为原始值;
- 需要清空缓存的场景(可考虑封装手动过期逻辑的 Map 替代方案)。
题目要点:
Map对引用类型键是强引用,可能导致内存泄漏;- 使用
WeakMap替代Map能在对象无外部引用时自动释放; WeakMap不可遍历,有使用上的限制,适合做“缓存”或“映射”用途;- 内存泄漏的本质是“无效引用被意外保留”,选择合适的数据结构是避免此类问题的关键。