weakmap 和 weakset 通过弱引用机制支持对象被垃圾回收,但需正确使用:键必须是真实对象且校验类型,值仍为强引用需谨慎管理,weakset 仅适用于标记场景,应封装为模块级单例。

WeakMap 和 WeakSet 本身不“避免”内存泄漏,而是通过弱引用机制,让对象能被垃圾回收器正常清理——前提是用对了方式。关键不在结构本身,而在你如何组织引用关系。
WeakMap 的键必须是真实对象且只用一次
WeakMap 的键只能是对象,而且这个对象得是你真正想绑定生命周期的那个实体。比如 DOM 元素、类实例(this),不能是字符串、数字或临时空对象。
- ✅ 正确:用
element本身当键,不是它的id - ✅ 正确:在类构造函数里用
this当键,存私有字段 - ❌ 错误:每次 new 类都新建一个 WeakMap 实例,失去弱引用意义
- ❌ 错误:传入
null或非 Node 对象,导致运行时错误或逻辑失效
务必校验:if (node && node instanceof Node) 再 set,否则容易出错。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
WeakMap 的值仍为强引用,需单独管理
WeakMap 只对键弱引用,值还是强引用。如果值里存了对键的反向引用,或者被定时器、全局变量、未注销的事件监听器长期持有,照样泄漏。
- 避免在值中写
{ owner: node }这类强反向引用 - 不要把
get()返回的对象塞进setInterval或全局缓存里 - 值尽量轻量:用简单对象、数字、布尔,别塞整个组件实例或大数组
WeakSet 适合标记而非存储
WeakSet 只能存对象,不能存基本类型,也不提供遍历和 size。它最自然的用途是“标记”某个对象是否已被处理过,且不阻碍其回收。
- 可用于事件只绑定一次:
if (!observed.has(el)) { observed.add(el); el.addEventListener(...) } - 可用于防重复初始化:节点被移除后,WeakSet 中对应条目自动消失
- 不能用来统计已处理数量,也不能做批量操作——它不支持这些
必须封装成模块级单例
多个 WeakMap/WeakSet 实例不仅浪费内存,还会让状态分散、难以维护。应统一导出一个模块级实例,并限制接口。
- 顶层声明:
const elementState = new WeakMap(); - 提供带防护的读写方法,比如
setElementState(node, data)内部校验类型 - 避免直接暴露 WeakMap 实例,防止误传 Window、Array 等非法键
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










