weakmap 解决内存泄漏的核心在于键的弱引用机制:当对象仅被 weakmap 键引用且无其他强引用时,gc 可立即回收该对象,对应条目自动消失;键必须为对象,值为强引用,不可遍历,不保证即时清理。

WeakMap 解决内存无法回收,核心在于它不“拖住”对象——当一个对象只被 WeakMap 的键引用着,而其他地方再没强引用,垃圾回收器(GC)就能立刻把它收走,对应条目也自动消失。
关键机制:键是弱引用,不参与可达性判定
JavaScript 的 GC 依靠“可达性”判断对象是否该回收:从全局变量、调用栈等根节点出发,能顺着强引用链访问到的对象,才算“活着”。WeakMap 的键不在这条链上——它对键的引用被 GC “无视”,相当于给对象发了一张“特赦令”。
- 普通 Map 的键是强引用:哪怕 DOM 元素已被 removeChild 移除,只要还在 Map 里,GC 就认为它“可达”,一直留在内存
- WeakMap 的键是弱引用:元素一被移除且外部无其他引用,GC 下次运行时就清理它,WeakMap 内部条目同步失效
典型泄漏场景对比:DOM 元素缓存
比如为每个按钮记录点击次数:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 用 Map:
map.set(button, { count: 0 })→ button 被删后仍驻留内存,计数数据也卡住 - 用 WeakMap:
wm.set(button, { count: 0 })→ button 被删且无其他引用,GC 回收 button,wm 条目自动消失,干净彻底
使用时必须守住的三条线
WeakMap 不是“自动清内存开关”,用错反而埋雷:
- 键只能是对象:字符串、数字、null 都会报错,因为原始值本身不可被弱引用
- 值仍是强引用:别在值里存对键的反向引用(如闭包捕获 this),否则形成循环,GC 还是动不了它
- 不保证“立刻清理”:GC 时机由引擎决定,条目可能短暂残留;逻辑上应视作“最终会消失”,而非“马上没了”
它适合做什么,不适合做什么
WeakMap 的定位很清晰:给对象挂私有元数据,且不想干预它的生命周期。
- 适合:DOM 状态标记、类实例的私有字段、第三方对象的配置缓存
- 不适合:需要遍历所有条目、序列化保存、做全局唯一标识、或依赖 size 判断容量
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










