当WeakMap本身在v8中进行GC编辑时,值会发生什么

时间:2016-01-30 13:32:17

标签: javascript ecmascript-6 v8

当密钥的生命周期短于Map本身的生命周期时,WeakMaps非常有用。但是,我可以想象当地图的生命和密钥的生命完全独立时的情况(即WeakMap本身可以在其中一个密钥之前被垃圾收集):

var wm = new WeakMap();
var obj = {};
wm.set(obj, someHeavyData); 
wm = null; // obj is still alive. 

在上面的示例中,obj仍然存在。但是,由于最初的WeakMap被垃圾收集,我们无法再访问someHeavyData。因此,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中的对象的原因)并且直到密钥本身是垃圾收集。

有人可以告诉我,我错了,它会被垃圾收集吗?

当我事先知道地图将在其键之前被垃圾收集时,可以告诉我在WeakMap上选择Map。不幸的是,如果事先不知道,有很多合法的情况。例如,二维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;

在此意图中,我们希望只要bobalice进行GC编辑就可以对HugeSecretData进行GC编辑。并且看起来只有当第二个密钥(即bob)被垃圾收集时它才会被GC编辑。

再一次:任何人,请告诉我我错了,并解释这些数据将如何以及何时被垃圾收集。

1 个答案:

答案 0 :(得分:1)

应该回答你的问题:

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)填补你的记忆需要几秒钟。