我有一些非常大的对象,它们被频繁地使用,但偶尔在我的Node.JS程序中使用。加载这些对象是昂贵的。总的来说,它们占用的内存比我在系统中的内存还多。有没有办法在JavaScript中创建一个“弱引用”,这样垃圾收集器就会在内存不足时删除我的对象,然后我可以检查对象是否被垃圾收集,如果它在我上次访问后被垃圾收集了,就重新加载它?我想到的特定用例是制图重投影和对千兆字节的Map图像进行平铺。
zour9fqk1#
有没有办法在JavaScript中创建一个“弱引用”,这样垃圾收集器就会在内存不足时删除我的对象?JavaScript没有这个。我不认为weakMap或weakSet会提供你想要做的事情。它们不会做你想要做的事情。相反,它们允许你引用一些不会禁止垃圾收集的东西。但是,如果没有其他对数据的引用,那么下次gc运行时它会立即被垃圾收集。所以,它们不会像你希望的那样将数据保存一段时间。如果你有任何其他对这些对象的引用,(为了保持它们在周围),那么它们永远不会被垃圾收集。JavaScript不提供弱引用,只有当内存开始变满时才被垃圾收集。有些东西要么符合垃圾收集条件,要么不符合。如果它符合条件,它将在下一次GC传递中被释放。听起来你可能需要一个内存缓存。你可以决定该高速缓存有多大,然后根据某种策略将项目保存在该高速缓存中。最常见的策略是LRU(最近最少使用),当您达到该高速缓存大小限制并且需要在该高速缓存中加载新项时,将项踢出该高速缓存。使用LRU,如果你试图管理缓存到一个内存使用量大小,你将必须有一些计划来估计缓存中对象的内存使用量。请注意,许多数据库本质上会将此功能作为内置功能提供给您,因为它们通常会包含某种缓存本身,因此如果您从最近请求的数据库中请求一个项目,它可能来自读缓存。您并没有真正说出您的对象是什么,因此我们很难确切地建议如何从数据库中使用它们。
weakMap
weakSet
l2osamch2#
自从引入WeakRef以来,这是可能的,但这是否真的有用值得怀疑。下面是一个演示,当然这取决于垃圾收集器的工作原理,所以不能保证什么时候对象会被垃圾收集。唯一可以保证的是,只要脚本的同步部分正在运行,垃圾收集就不会发生,所以第一个输出将报告所有对象都是活的,即使我们不再有对它们的强引用:
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 livefunction 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}
// 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
}
字符串
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; }}
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();}
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());}
let strongRefs = [];
await nextTick();
strongRefs.push(new Thing().getBigData());
型
3条答案
按热度按时间zour9fqk1#
有没有办法在JavaScript中创建一个“弱引用”,这样垃圾收集器就会在内存不足时删除我的对象?
JavaScript没有这个。
我不认为
weakMap
或weakSet
会提供你想要做的事情。它们不会做你想要做的事情。相反,它们允许你引用一些不会禁止垃圾收集的东西。但是,如果没有其他对数据的引用,那么下次gc运行时它会立即被垃圾收集。所以,它们不会像你希望的那样将数据保存一段时间。如果你有任何其他对这些对象的引用,(为了保持它们在周围),那么它们永远不会被垃圾收集。JavaScript不提供弱引用,只有当内存开始变满时才被垃圾收集。有些东西要么符合垃圾收集条件,要么不符合。如果它符合条件,它将在下一次GC传递中被释放。听起来你可能需要一个内存缓存。你可以决定该高速缓存有多大,然后根据某种策略将项目保存在该高速缓存中。最常见的策略是LRU(最近最少使用),当您达到该高速缓存大小限制并且需要在该高速缓存中加载新项时,将项踢出该高速缓存。使用LRU,如果你试图管理缓存到一个内存使用量大小,你将必须有一些计划来估计缓存中对象的内存使用量。
请注意,许多数据库本质上会将此功能作为内置功能提供给您,因为它们通常会包含某种缓存本身,因此如果您从最近请求的数据库中请求一个项目,它可能来自读缓存。您并没有真正说出您的对象是什么,因此我们很难确切地建议如何从数据库中使用它们。
l2osamch2#
自从引入
WeakRef
以来,这是可能的,但这是否真的有用值得怀疑。下面是一个演示,当然这取决于垃圾收集器的工作原理,所以不能保证什么时候对象会被垃圾收集。唯一可以保证的是,只要脚本的同步部分正在运行,垃圾收集就不会发生,所以第一个输出将报告所有对象都是活的,即使我们不再有对它们的强引用:
字符串
lpwwtiir3#
根据具体情况,JavaScript的WeakRef可能支持您的用例。
例如,假设您有一个带有getter的类,该类返回一个数据对象,该数据对象的内存占用量足够大,以至于您只能同时存储几个这样的对象。
个字符
警告:下面仍然会导致内存不足错误,因为从WeakRef添加或提取的项目直到当前tick的 end 才能被GC'd。
型
警告:下面仍然会导致内存不足错误,因为额外的强引用将保留数据,尽管在单独的滴答声中运行。
型