【问题标题】:Forcing garbage collection in Node to test WeakRef and FinalizationRegistry在 Node 中强制进行垃圾回收以测试 WeakRef 和 FinalizationRegistry
【发布时间】:2021-03-18 09:14:06
【问题描述】:

我正在使用WeakRef and FinalizationRegistry in V8,但我无法验证以下代码在 Node.js 中是否确实有效。

我正在使用 Node v15.3.0 并像这样运行它:

node --expose-gc transient.js:

我希望在控制台日志中看到一些 finalizerCallback called! 条目。

如果我在基于 Chromium 的浏览器中运行它(尝试 Run code snippet 按钮),如果单击 DevTools 的性能部分(在 Chrome v87 中)中的垃圾图标(收集垃圾),我可以获得该输出,而异步脚本仍在运行。

它在 Firefox v83 中按预期工作,脚本结束时我看到所有终结器回调。

对于 Node,我希望在显式调用垃圾回收时自动看到它,但根本不会调用终结器回调。

是不是代码本身有问题,或者有没有更可靠的方式在Node中强制GC?

// by @noseratio
// see https://v8.dev/features/weak-references

class Transient {
  constructor(eventTarget) {
    const finalizerCallback = ({ eventTarget, eventListener }) => {
      console.log('finalizerCallback called!');
      eventTarget.removeEventListener('testEvent', eventListener);
    }
    const finalizer = new FinalizationRegistry(finalizerCallback);

    const strongRefs = { finalizer };
    const weakRef = new WeakRef(this);
    const eventListener = () => {
      console.log('eventListener called!');
      strongRefs.finalizer = null;
      weakRef.deref()?.test();
    }

    finalizer.register(this, { eventTarget, eventListener });

    eventTarget.addEventListener('testEvent', eventListener, { once: true });
  }

  test() {
    console.log("test called!");
  }
}

async function main() {
  const gc = globalThis?.global?.gc;
  console.log(`garbage collector func: ${gc}`);

  const eventTarget = new EventTarget();

  for (let i = 10; i > 0; i--) {
    void function () {
      // these instances of Transient really must be getting GC'ed!
      new Transient(eventTarget);
    }();
  
    await new Promise(r => setTimeout(() => r(gc?.(true)), 100));
  }

  console.log("finishing...")
  gc?.(true);
  await new Promise(r => setTimeout(r, 5000));

  eventTarget.dispatchEvent(new Event("testEvent"));
  console.log("done.")
}

main().catch(console.error);

更新,如果我增加 for 循环集成的数量,我最终会看到一些 finalizerCallback 调用,但它们仍然是零星的。

【问题讨论】:

    标签: javascript node.js garbage-collection v8


    【解决方案1】:

    我直接从@jasnell 得到了the answer:

    你可以试试原生语法函数%CollectGarbage

    我已经尝试过了,它完全符合我的要求。在现实生活中,它是一个AbortController 对象链,更多上下文here。

    启用%CollectGarbage:

    node --allow-natives-syntax Transient.js
    

    要对静态代码分析器隐藏% 语法,我们可以使用eval:

    eval("%CollectGarbage('all')");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-09
      • 1970-01-01
      • 2012-12-06
      • 2015-11-16
      • 1970-01-01
      • 2011-01-26
      • 2010-09-16
      相关资源
      最近更新 更多