散文吧>Yorkie想升级>日记>日记|WeakMap与弱引用

日记|WeakMap与弱引用

2016-07-06 00:52 | Yorkie想升级

日记|WeakMap与弱引用


旅行的意义在于敞开自己的心扉,去接纳别人看似奇怪却合其理的想法,并相互尊重,成为朋友


WeakMap与弱引用(Weak Reference)


今天在改 Fibula.js 代码的时候,我决定引入一个内部的对象来缓存每次都要运行的一个结果集,于是我打算使用WeakMap来试试,不过结果却得到了下面的错误:


TypeError: Invalid value used as weak map key
    at WeakMap.set (native)


于是我就纳闷了,我明明是这样使用的:


let dirs = new WeakMap();
// balabala...
dirs.set('name', []);


于是我先是去查v8的代码,我很快就定位到错误是在src/js/weak-collection.js的第70行处:


function WeakMapSet(key, value) {  
if (!IS_WEAKMAP(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver, 'WeakMap.prototype.set', this); }
if (!IS_SPEC_OBJECT(key))
throw MakeTypeError(kInvalidWeakMapKey); // 就是此处
return %WeakCollectionSet(this, key, value, GetHash(key)); }


然后我就有个疑问,为什么只有当key的值是对象(Object)才可以呢,后来我又查了下MDN,得到如下解释:


The key in a WeakMap is held weakly. What this means is that, if there are no other strong references to the key, then the entire entry will be removed from the WeakMap by the garbage collector.


读到这里,我明白了为什么会报错,但是看到什么"strong reference"什么的,我整个人还是不好的,为了弄明白为什么要这么设计,我继续查资料,于是找了下面这段代码:


Counter counter = new Counter(); // strong reference - line 1 
WeakReference<Counter> weakCounter = new WeakReference<Counter>(counter); //weak reference
counter = null; // now Counter object is eligible for garbage collection


我就恍然大悟,于是我有了这样的对弱引用的解释:


弱引用即 WeakMap 中的键(Key)是指向一个对象(Object),但是这个引用并不会在垃圾回收器判断对象是否被回收时影响其结果,也就是说弱引用(Weak Reference)是一个单向引用。


这样一种特性被用在键值对(Key/Value)真是一种比较内存友好的实现方式,比如:


var map = new WeakMap();
function init(map) {
var key = new String('this is a key');
map.set(key, '任意值'); }
init(map);


上面的代码,在我们调用完init函数之后,由于key是在函数内定义的,所以当函数结束,尽管我们在一个全局作用域下的WeakMap中引用了它,但由于是弱引用(Weak Reference),所以key最后还是会被回收掉。


如果上面的代码,我们换成是{}或者Map,那么key无疑会被保护,一直到map先被回收为止。所以这类引用方式其实就是通过代码进行key的约定,并且对key没有特别的要求。


然后我又回过头去看了一下WeakMapMap的API,并进行了对比,发现Map相较于前者,多了Map.prototyoe.entries(类似于Object.keys),因此我们也不能在WeakMap对象上进行遍历操作了。


WeakMap特别适合这类应用:当我有一个需要长时间维护的键值对集合,这个集合会被在程序多处使用,然后再各自使用完后,可以放心地新建对象作为键(Key),而不用担心由于循环引用而造成相关对象一直无法释放的情况了。


所以,原来一直说的 Node.js 不适合维护长周期变量的最佳实践应该也不复存在了。




Yorkie想升级
Yorkie想升级
公众号:yorkie_ninja
分享生活 享受生活