当键的生命周期短于Map自身的生命周期时,WeakMap很有用。但是,我可以想象这样一种情况,即地图的生命周期和键的生命周期是完全独立的(即WeakMap本身可以在其中一个键之前被垃圾回收):
var wm = new WeakMap();
var obj = {};
wm.set(obj, someHeavyData);
wm = null; // obj is still alive.
在上面的示例obj
中仍然有效。但是,someHeavyData
由于原始的WeakMap已被垃圾回收,因此我们无法再访问了。因此,也someHeavyData
应该进行垃圾收集。不过,我怀疑它不会被GC处理,并且会产生内存泄漏,因为(据我了解)v8中的WeakMaps是通过某种方式(大致)实现的:
class WeakMap {
constructor() {
this.symbol = Symbol();
}
get(key) {
return key[this.symbol];
}
set(key, value) {
key[this.symbol] = value;
return this;
}
}
这意味着,如果任何数据曾经存储在某个弱映射的键下,则将其作为强引用存储在键中(这就是为什么键应该是WeakMaps中的对象的原因),并且直到键本身才会被垃圾回收被垃圾收集。
谁能告诉我我错了,并且会被垃圾回收吗?
当我提前知道地图将在其键之前被垃圾收集时,可以告诉我选择Map而不是WeakMap。不幸的是,有很多合理的情况无法事先得知。例如,二维WeakMap:
class WeakMap2D {
constructor () {
this.wm1 = new WeakMap();
}
get(key1, key2) {
var vm2 = this.vm1.get(key1);
return vm2 && vm2.get(key2);
}
set(key1, key2, value) {
var vm2 = this.vm1.get(key1);
if (!vm2) {
vm2 = new WeakMap();
this.vm1.set(key1, vm2);
}
vm2.set(key2, value);
return this;
}
}
使用此类,我们可以编写:
var secrets = new WeakMap2D();
var alice = {}, bob = {};
secrets.set(alice, bob, HugeSecretData);
alice = null;
出于此目的,我们希望HugeSecretData应尽快bob
或alice
由GC进行GC处理。而且看起来只有当第二个键(即bob
)被垃圾回收时,它才会被GC处理。
再说一次:任何人,请告诉我我错了,并说明如何以及何时垃圾收集这些数据。
应该回答你的问题:
var obj = {}
var weakmap = null;
while(true) {
weakmap = new WeakMap()
weakmap.set(obj, new Uint32Array(2048))
}
如您所见,obj永远不会被释放,而是weakmap
被更改为新weakmap
的,而旧的应该被释放。如果我在中运行NodeJS
它,它将释放内存,并且这个无限循环最终不会占用所有内存。就是说,WeakMap
它正在按预期工作,并且没有内存泄漏。您认为key
继续引用的假设value
是错误的,因为在这种情况下,那WeakMap
将不是真实的WeakMap
。
需要花费几秒钟的时间来填补您的记忆Uint32Array(2048)
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句