You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript/JavaScript:此WeakMap‘技巧’能否达到预期效果?

用WeakMap维护类实例并支持垃圾回收的正确姿势

首先直接给结论:如果你的Person实例不是WeakMap的键,那这个方案完全不可行。

WeakMap的弱引用特性仅针对它的键——只有当键是对象时,WeakMap才不会阻止该对象被垃圾回收。如果实例是存在WeakMap的值里,WeakMap会对值保持强引用,和用普通数组存实例没有任何区别,实例依然无法被垃圾回收。


正确实现思路:结合WeakRef与FinalizationRegistry

要实现「既能追踪所有存活实例,又不阻止垃圾回收」的需求,单纯用WeakMap/WeakSet不够,因为它们不支持遍历操作。ES2021引入的WeakRef(弱引用)和FinalizationRegistry(终结器)可以完美解决这个问题:

  • 用WeakRef存储实例的弱引用,不会阻止实例被回收
  • 用FinalizationRegistry监听实例的回收事件,自动清理失效的弱引用
  • 维护一个普通集合存储WeakRef,遍历的时候过滤出还存活的实例

代码示例

class Person {
  constructor(name) {
    this.name = name;
    InstanceTracker.register(this);
  }
}

class InstanceTracker {
  // 存储实例的WeakRef,方便后续遍历
  static #weakRefs = new Set();
  // 终结器:实例被回收时自动清理对应的WeakRef
  static #cleanupRegistry = new FinalizationRegistry(weakRef => {
    InstanceTracker.#weakRefs.delete(weakRef);
  });

  // 注册实例到追踪系统
  static register(instance) {
    const ref = new WeakRef(instance);
    InstanceTracker.#weakRefs.add(ref);
    // 关联实例与WeakRef,实例回收时触发清理
    InstanceTracker.#cleanupRegistry.register(instance, ref);
  }

  // 获取所有当前存活的实例
  static getAliveInstances() {
    const aliveInstances = [];
    // 遍历WeakRef集合,过滤出还存活的实例,同时清理失效引用
    for (const ref of InstanceTracker.#weakRefs) {
      const instance = ref.deref();
      if (instance) {
        aliveInstances.push(instance);
      } else {
        InstanceTracker.#weakRefs.delete(ref);
      }
    }
    return aliveInstances;
  }
}

测试验证方法

Node.js环境测试(需手动触发GC)

  1. 启动Node.js时添加--expose-gc参数,允许手动调用垃圾回收
  2. 执行以下代码:
// 创建实例
let alice = new Person('Alice');
let bob = new Person('Bob');

console.log(InstanceTracker.getAliveInstances().length); // 输出 2

// 解除所有强引用
alice = null;
bob = null;

// 手动触发垃圾回收
global.gc();

console.log(InstanceTracker.getAliveInstances().length); // 输出 0

浏览器环境测试

  1. 打开浏览器控制台,创建实例:let testPerson = new Person('Test');
  2. 打开DevTools的「Memory」面板,拍摄一次堆快照,搜索Person,能看到该实例
  3. 解除引用:testPerson = null;
  4. 点击Memory面板的垃圾桶按钮触发垃圾回收,再拍一次快照
  5. 再次搜索Person,应该找不到该实例;同时调用InstanceTracker.getAliveInstances()会返回空数组

内容的提问来源于stack exchange,提问作者user3767443

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:07:04