【JS】WeakMap和WeakRef -----解决 内存泄漏 和 内存管理效率 问题

100 阅读4分钟

1. WeakMap 是什么?

WeakMap 内部结构:
[ {弱引用: 键对象} -> {值} ]

当“键对象”被回收,WeakMap 自动删除该条目。

生活中类比

想象你在咖啡厅有个「储物柜」,每个储物柜对应一个顾客的「包包」。

  • 你想存包包里的东西(比如钥匙、手机)放到柜子里,柜子是根据包包来识别的。
  • 重要的是:如果顾客拿走了包包(包包不见了),你也不想一直占着柜子,这个柜子能自动清理空柜子。

在代码中

  • WeakMap 的键只能是对象(这里就是包包),值可以是任何数据(包包里的东西)。
  • 当这个键(对象)没有别的引用了(顾客离开了,包包不见了),垃圾回收机制会自动清理 WeakMap 里对应的条目。
  • 你不能遍历 WeakMap(因为这些键随时可能被清理,遍历会不稳定)。

用途举例:

  • 存储某个 DOM 元素相关的数据,当元素被删除时,相关数据也自动被清理。
  • 存储某个对象的私有信息,不暴露到外面,且不会阻止这个对象被销毁。

2. WeakRef 是什么?

生活中类比

你想看某位朋友,但不想硬拉着他(不给他压力)。
你留了一个「电话薄」上的号码(弱引用),想打电话给他:

  • 如果朋友还在,你能打电话找到他。
  • 但如果朋友已经搬走了(被垃圾回收了),你拿电话也联系不上了。

在代码中

  • WeakRef 是一个对象的弱引用。
  • 你不能直接保证这个对象一定还在,用 .deref() 尝试拿对象,可能拿到,也可能拿不到(对象被回收了)。
  • 适合缓存或者监听那些“存在即使用,消失则无所谓”的对象。

用途举例:

  • 缓存一些大对象,比如图片、模型,允许内存紧张时回收。
  • 观察者模式里存弱引用,避免订阅者对象一直被占用。

📝 总结对比

方面WeakMapWeakRef
键类型只能是对象持有一个对象的弱引用
作用关联对象与数据,不阻止对象回收弱引用某对象,允许回收,需手动取值
是否可遍历不可不是容器,不可遍历
典型用途存储对象的私有数据或状态缓存对象、观察者、资源管理

你可以把:

  • WeakMap 想成「根据对象自动管理私有数据的柜子」;
  • WeakRef 想成「能随时失效的轻薄引用,拿不拿到对象由 GC 决定」。

⚠️WeakMap和WeakRef主要是为了解决什么问题?

WeakMapWeakRef 主要是为了解决 内存泄漏内存管理效率问题,帮助程序更智能地管理对象生命周期,避免无用数据长期占用内存。

WeakMap 主要解决的问题

1. 对象相关数据的自动垃圾回收

  • 传统的 Map 用对象做键时,只要 Map 里有引用,这些对象就不会被回收。

  • 可能导致内存泄漏:即使对象不再使用了,但相关数据依然占用内存。

  • WeakMap 的键是弱引用,当键对象不再被其他地方引用,垃圾回收机制会自动清除对应的数据。

举例:你给 DOM 元素存一些数据,如果元素被删除了,相关数据自动被清理,避免内存泄漏。


WeakRef 主要解决的问题

2. 缓存和资源管理中的“软引用”

  • 有些缓存不想强制保留对象(避免内存占用过大),又想有机会访问。

  • 传统的缓存(Map + 对象引用)会一直保留对象,导致内存占用。

  • WeakRef 允许对对象持有“弱引用”,不阻止垃圾回收

  • 对象不被强引用时可能被回收,缓存变“软”,系统内存紧张时能自动释放。

举例:图片、模型等大资源缓存,用 WeakRef 保存,内存紧张时自动释放。


总结

问题传统方案的痛点WeakMap / WeakRef 解决方案
对象关联数据的内存泄漏Map 持有强引用,导致对象无法释放WeakMap 通过弱引用键自动清理
缓存资源占用过多内存强引用缓存导致内存占用WeakRef 允许缓存对象被回收,节省内存

啥是WeakMap和Map?啥是弱引用、强引用?,请看➡️ 点击链接