在 Javascript 中使用弱引用查找表 [英] Lookup table with weak references in Javascript

查看:32
本文介绍了在 Javascript 中使用弱引用查找表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个动态添加和删除元素的树结构.这些元素是从网络动态加载的.我想要实现的是有一个查找表,将元素的 id 映射到树中的实际元素.现在,使用简单的 Map 或 Object 时的问题是它持有对树元素的强引用,这会在一段时间后使内存膨胀.由于节点 >= 14.6.0 和 Chrome >= 84 据说支持 WeakRef 我想我可以制作一个 Map ,将 WeakRefs 保存到我的树元素,然后简单地 deref() 并查看元素是否仍然存在.我试图对此进行测试,但似乎不起作用.我的最小测试如下所示:

I have a tree structure with elements dynamically added and removed. The elements are loaded dynamically from the network. What I want to achieve is to have a lookup table that maps the element's id to the actual element in the tree. Now, the problem when using a simple Map or Object is that it holds strong references to the tree elements which will bloat the memory after a while. Since node >= 14.6.0 and Chrome >= 84 supposedly support WeakRef's I thought I could make a Map that holds WeakRefs to my tree elements and then simply deref() and see if the elements are still around. I tried to test this but it doesn't seem to work. My minimal test looks like this:

const lookup = new Map();
let element = new Object({id:"someid", data: {}});

lookup.set(element.id, new WeakRef(element));
console.dir(lookup.get("someid").deref());
// as expected output is { id: 'someid', data: {} }

element = null;
console.log(element);
// as expected output is null

// simply calling global.gc() didn't work
// so i made this loop which allocates mem *and* calls global.gc() to
// force garbage collection
// problem: infinite loop because deref always returns the dereferenced
// value which should have gone since element was set to null

while (lookup.get("someid").deref()) {
  const a = new Array(1000);
  // enabled with --expose-gc in node
  global.gc();
}

console.dir(lookup.get("someid").deref());

正如上面评论中所写,问题是循环永远不会结束因为 deref 调用总是返回一个值,尽管元素 var被设置为空.

As written above in the comment, the issue is that the loop never ends because the deref call always returns a value despite the element var being set to null.

我在这里遗漏了什么吗?如果没有,这就是它应该如何工作,我怎样才能实现拥有弱引用映射的目标(WeakMap 不是这里有一个选项,因为我通过 id 查找元素的成本为 O(n)?.

Am I missing something here? If not and this is how it is supposed to work, how can I achieve my goal of having a map of weak references (WeakMap is not an option here, since I would have an O(n) cost of looking up an element by id)?.

推荐答案

我在这里遗漏了什么吗?

Am I missing something here?

是的:您遗漏了 文档您已链接到,例如:

Yes: you're missing the notes in the documentation you've linked to, for instance:

如果您的代码刚刚为目标对象创建了一个 WeakRef,或者已经从 WeakRef 的 deref 方法中获取了一个目标对象,则该目标对象将不会在当前 JavaScript 作业(包括任何承诺反应作业)结束之前被回收在脚本作业结束时运行).也就是说,你只能看到"一个对象在事件循环的轮次之间被回收.

If your code has just created a WeakRef for a target object, or has gotten a target object from a WeakRef's deref method, that target object will not be reclaimed until the end of the current JavaScript job (including any promise reaction jobs that run at the end of a script job). That is, you can only "see" an object get reclaimed between turns of the event loop.

当然还有:

尽可能避免
正确使用 Wea​​kRef 需要仔细考虑,如果可能,最好避免使用.避免依赖规范未保证的任何特定行为也很重要.垃圾收集何时、如何以及是否发生取决于任何给定 JavaScript 引擎的实现.

Avoid where possible
Correct use of WeakRef takes careful thought, and it's best avoided if possible. It's also important to avoid relying on any specific behaviors not guaranteed by the specification. When, how, and whether garbage collection occurs is down to the implementation of any given JavaScript engine.

也就是说,实现您的目标是完全可能的;您的测试用例太简单(根据上面引用的注释)无法显示.这是一个固定版本:

That said, achieving your goal is totally possible; your test case is just too simple (in light of the notes quoted above) to show it. Here's a fixed version:

const lookup = new Map();

(function () {
  let element = { id: "someid", data: {} };
  lookup.set(element.id, new WeakRef(element));
  element = null;

  console.log(lookup.get("someid").deref());

  setTimeout(() => {
    global.gc();
    console.log(lookup.get("someid").deref());
  }, 0);
})();

这篇关于在 Javascript 中使用弱引用查找表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆