Open yorkie opened 8 years ago
其实就是js的字符串字面量不是object,而weak是对object垃圾收集做手脚,所以不匹配。归根结底是语言设计问题。c#或java也有弱引用,传字符串字面量就没问题。
另外,string在使用被自动ToObject是约定俗成的东西,之所以weakmap实现中不这样,是因为基本类型虽然有对应的object形式,但设计上无共享语义(使得实现上可以共享而进行优化),你绕过了这个设计限制而已。简单讲:a=new String('abc'); b=a;则显然b与a指向同一片内存,但a=new String('abc'); b=new String('abc'); 则b与a是否指向同一片内存是未定义的。另外实在没必要用weakmap防止string这种小东西无法被回收,因为weakmap内部会根据这个string的地址生成另一个更复杂的标识对象,那个内存和cpu的overhead比起用map完全是倒退~
好的吧~
WeakMap与弱引用(Weak Reference)
今天在改 Fibula.js 代码的时候,我决定引入一个内部的对象来缓存每次都要运行的一个结果集,于是我打算使用
WeakMap
来试试,不过结果却得到了下面的错误:于是我就纳闷了,我明明是这样使用的:
于是我先是去查v8的代码,我很快就定位到错误是在
src/js/weak-collection.js
的第70行处:然后我就有个疑问,为什么只有当
key
的值是对象(Object)才可以呢,后来我又查了下MDN,得到如下解释:读到这里,我明白了为什么会报错,但是看到什么"strong reference"什么的,我整个人还是不好的,为了弄明白为什么要这么设计,我继续查资料,于是找了下面这段代码:
我就恍然大悟,于是我有了这样的对弱引用的解释:
这样一种特性被用在键值对(Key/Value)真是一种比较内存友好的实现方式,比如:
上面的代码,在我们调用完
init
函数之后,由于key
是在函数内定义的,所以当函数结束,尽管我们在一个全局作用域下的WeakMap
中引用了它,但由于是弱引用(Weak Reference),所以key
最后还是会被回收掉。如果上面的代码,我们换成是
{}
或者Map
,那么key
无疑会被保护,一直到map
先被回收为止。所以这类引用方式其实就是通过代码进行key
的约定,并且对key
没有特别的要求。然后我又回过头去看了一下
WeakMap
和Map
的API,并进行了对比,发现Map
相较于前者,多了Map.prototyoe.entries
(类似于Object.keys
),因此我们也不能在WeakMap
对象上进行遍历操作了。WeakMap
特别适合这类应用:当我有一个需要长时间维护的键值对集合,这个集合会被在程序多处使用,然后再各自使用完后,可以放心地新建对象作为键(Key),而不用担心由于循环引用而造成相关对象一直无法释放的情况了。所以,原来一直说的 Node.js 不适合维护长周期变量的最佳实践应该也不复存在了。