NodeJS 如何在JavaScript中使用弱引用?

tjvv9vkg  于 9个月前  发布在  Node.js
关注(0)|答案(3)|浏览(143)

我有一些非常大的对象,它们被频繁地使用,但偶尔在我的Node.JS程序中使用。加载这些对象是昂贵的。总的来说,它们占用的内存比我在系统中的内存还多。
有没有办法在JavaScript中创建一个“弱引用”,这样垃圾收集器就会在内存不足时删除我的对象,然后我可以检查对象是否被垃圾收集,如果它在我上次访问后被垃圾收集了,就重新加载它?
我想到的特定用例是制图重投影和对千兆字节的Map图像进行平铺。

zour9fqk

zour9fqk1#

有没有办法在JavaScript中创建一个“弱引用”,这样垃圾收集器就会在内存不足时删除我的对象?
JavaScript没有这个。
我不认为weakMapweakSet会提供你想要做的事情。它们不会做你想要做的事情。相反,它们允许你引用一些不会禁止垃圾收集的东西。但是,如果没有其他对数据的引用,那么下次gc运行时它会立即被垃圾收集。所以,它们不会像你希望的那样将数据保存一段时间。如果你有任何其他对这些对象的引用,(为了保持它们在周围),那么它们永远不会被垃圾收集。JavaScript不提供弱引用,只有当内存开始变满时才被垃圾收集。有些东西要么符合垃圾收集条件,要么不符合。如果它符合条件,它将在下一次GC传递中被释放。
听起来你可能需要一个内存缓存。你可以决定该高速缓存有多大,然后根据某种策略将项目保存在该高速缓存中。最常见的策略是LRU(最近最少使用),当您达到该高速缓存大小限制并且需要在该高速缓存中加载新项时,将项踢出该高速缓存。使用LRU,如果你试图管理缓存到一个内存使用量大小,你将必须有一些计划来估计缓存中对象的内存使用量。
请注意,许多数据库本质上会将此功能作为内置功能提供给您,因为它们通常会包含某种缓存本身,因此如果您从最近请求的数据库中请求一个项目,它可能来自读缓存。您并没有真正说出您的对象是什么,因此我们很难确切地建议如何从数据库中使用它们。

l2osamch

l2osamch2#

自从引入WeakRef以来,这是可能的,但这是否真的有用值得怀疑。
下面是一个演示,当然这取决于垃圾收集器的工作原理,所以不能保证什么时候对象会被垃圾收集。唯一可以保证的是,只要脚本的同步部分正在运行,垃圾收集就不会发生,所以第一个输出将报告所有对象都是活的,即使我们不再有对它们的强引用:

// Create lots of objects with an `i` property:
let weakrefs = Array.from({length: 100000}, (_, i) =>
    new WeakRef({ i })
);
// Let's poll now and then how many of them are still live...
loop(); // This runs synchronously, so it will report all of them to be live
function loop() { 
    let liveCount = weakrefs.reduce((count, weakref) => count + !!weakref.deref(), 0);
    console.log(liveCount + " objects are still live");
    setTimeout(loop, 1000); // Wait one second and repeat
}

字符串

lpwwtiir

lpwwtiir3#

根据具体情况,JavaScript的WeakRef可能支持您的用例。
例如,假设您有一个带有getter的类,该类返回一个数据对象,该数据对象的内存占用量足够大,以至于您只能同时存储几个这样的对象。

class Thing {
  getBigData() {
    let bigData = this.ref?.deref();

    if (bigData === undefined) {
      bigData = new BigData(); // <-- allocates many GB
      this.ref = new WeakRef(bigData) ;
    }

    return bigData;
  }
}

个字符
警告:下面仍然会导致内存不足错误,因为从WeakRef添加或提取的项目直到当前tick的 end 才能被GC'd。

for (let i=0; i<1000; i++) {
  new Thing().getBigData();
}


警告:下面仍然会导致内存不足错误,因为额外的强引用将保留数据,尽管在单独的滴答声中运行。

let strongRefs = [];

for (let i=0; i<1000; i++) {
  await nextTick();
  strongRefs.push(new Thing().getBigData());
}

相关问题