我有一个树结构,其中动态添加和删除元素。这些元素是从网络动态加载的。我想要实现的是拥有一个查找表,将元素的 id 映射到树中的实际元素。现在,使用简单的映射或对象时的问题是它持有对树元素的强引用,这会在一段时间后使内存膨胀。由于节点 >= 14.6.0 且 Chrome >= 84据说支持 WeakRef https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef我想我可以制作一个将 WeakRefs 保存到我的树元素的 Map,然后简单地deref()
并查看元素是否仍然存在。我尝试对此进行测试,但似乎不起作用。我的最小测试如下所示:
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
被设置为空。
我在这里错过了什么吗?如果没有,这就是它应该如何工作的,
我怎样才能实现拥有弱引用映射的目标(WeakMap 不是
这里有一个选项,因为通过 id 查找元素的成本是 O(n)?。
我在这里错过了什么吗?
是的:您缺少注释中的注释文档 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef例如,您已链接到:
如果您的代码刚刚为目标对象创建了 WeakRef,或者从 WeakRef 的 deref 方法获取了目标对象,则该目标对象将不会被回收,直到当前 JavaScript 作业结束(包括在该作业运行的任何 Promise 反应作业)。脚本作业结束)。也就是说,您只能“看到”在事件循环的轮次之间回收对象。
而且当然:
尽可能避免
正确使用 WeakRef 需要仔细考虑,并且最好尽可能避免。避免依赖规范未保证的任何特定行为也很重要。何时、如何以及是否发生垃圾收集取决于任何给定 JavaScript 引擎的实现。
也就是说,实现你的目标是完全有可能的;您的测试用例太简单(根据上面引用的注释),无法显示它。这是一个固定版本:
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);
})();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)