WeakRef 和 FinalizationRegistry 允许监听对象被垃圾回收的时机而非干预 GC 过程;WeakRef 创建不阻止回收的引用,deref() 返回 undefined 表示对象已销毁;FinalizationRegistry 在对象回收后异步触发回调,适用于缓存清理等非关键场景。

WeakRef 和 FinalizationRegistry 本身不“手动管理”垃圾回收,也不能强制触发 GC,但可以让你在对象**被垃圾回收时及时获知并执行清理动作**。关键在于理解:GC 由引擎自动决定,你只能监听结果,不能干预过程。
WeakRef:让引用不拖住对象
WeakRef 创建一个不阻止目标对象被回收的引用。它像一张“临时入场券”,对象没人再需要时,这张票自动作废。
- 用
new WeakRef(obj)包裹大对象,比如一个大型 JSON 数据、Canvas 图像或 DOM 节点集合 - 后续通过
ref.deref()获取原对象;若返回undefined,说明对象已被回收 - ⚠️ 注意:WeakRef 不会自动从缓存或 Map 中删除自己——它只解决“不阻止回收”,不解决“如何清理残留引用”
FinalizationRegistry:对象一消失,你就收到通知
FinalizationRegistry 是真正的“回收哨兵”。你注册一个对象和一个“凭证值”,当该对象被 GC 回收后,回调函数就会被调用,并传入那个凭证值。
- 创建时传入回调:
const registry = new FinalizationRegistry((heldValue) => { console.log('对象已释放', heldValue); }); - 注册时绑定目标对象和凭证(如缓存 key、资源 ID、清理函数):
registry.register(largeObj, 'user-profile-data'); - 回调时机不确定(可能延迟数秒甚至更久),不可用于释放关键资源(如 WebSocket、文件句柄),但适合日志、统计、缓存条目清理等非关键操作
典型组合用法:软缓存自动清理
把 WeakRef 存进 Map,再用 FinalizationRegistry 在对象回收时删掉对应键,就能实现“用时不阻 GC,废时不占空间”的缓存。
- 缓存设为
Map<string weakref>></string>,避免强引用锁死大对象 - 每次
set(key, value)时,同时调用registry.register(value, key) - 回调里直接
cache.delete(key),清除 Map 中失效的条目 - 这样既防内存泄漏,又避免 Map 自身无限膨胀
实际注意事项
这些 API 不是“万能清道夫”,用错反而增加复杂度。
- 不要依赖 FinalizationRegistry 的回调时机做逻辑判断——它可能不触发、延迟触发,或在测试中因 GC 未运行而静默
- WeakRef.deref() 返回 undefined 后,不能再恢复对象;它只是告诉你“人已经走了”
- 若对象仍被闭包、事件监听器、定时器或全局变量持有,FinalizationRegistry 就永远不会触发回调
- 调试时可配合 Chrome DevTools 的 Memory 面板拍堆快照,确认大对象是否真被释放

















