博客园markdown不太好看,可以转到git阅读https://sologgfun.github.io/look/

const keyObject = ['keyObject'];
new WeakMap().set(keyObject, ['value']);

问题:现在 ['value'] 会被释放吗?

听说WeakMap是o(1)复杂度的,而且不会存在内存泄漏问题,那么就只有一种实现机制,就是value直接通过一个隐形键挂在keyObject上。

但如果是这样,而WeakMap本身又没有引用它之前添加过那些内容,那么是不是如果keyObject不释放,即便WeakMap实例释放了,通过该WeakMap实例添加在keyObject上的value是不是也都不会释放,从而形成另一种内存泄漏?

jsperf.com只能测试性能,不知道内存泄漏该如何测试?


答案:会正确被释放

测试过程:

[1]Chrome DevTools 控制台上有一个小众的 API 叫

queryObjects()

,它可以从原型树上反查所有直接或间接的继承了某个对象的其它对象,比如

queryObjects(Array.prototype)

可以拿到所有的数组对象,

queryObjects(Object.prototype)

则基本上可以拿到页面里的所有对象了(除了继承自Object.create(null)的对象之外)。而且关键是这个 API 会在内存里搜索对象前先进行一次垃圾回收

【测试1】

const key = new WeakMap();
const map = new WeakMap();
map.set(key, new WeakMap());
undefined;

在chrome控制台运行

查到了 3 个对象,符合预期

【测试2】

const key = new WeakMap();
new WeakMap().set(key, new WeakMap());
undefined;

在chrome控制台运行

只有一个WeakMap没有被回收


那么WeakMap是怎么做到的呢?

核心在于WeakMap上的kv对是弱引用的

V8 的实现,是在 GC 上开洞的

https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/objects/hash-table.h#L336

https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/heap/scavenger.cc#L465WeakMap

里用的就是这个 EphemeronHashTable,EphemeronHashTable 存储着的键和值都是弱引用

let wm = new WeakMap([[k1, v1], [k2, v2]]) // vm = {k1:v1, k2:v2}

wm.size // no such property

wm.keys(); // no such function

wm.forEach(...) // unable to be iterated

WeakMap有2个特点

  1. 属性不可枚举
  2. key必须是Object类型

看一下WeakMap的polyfill

var WeakMap = function() {
this.name = '__wm__' + uuid()
}; WeakMap.prototype = {
set: function(key, value) {
Object.defineProperty(key, this.name, {
value: [key, value],
});
return this;
},
get: function(key) {
var entry = key[this.name];
return entry && (entry[0] === key ? entry[1] : undefined);
},
...
};
  1. weakmap.set(key, val)事实上是直接通过Object.defineProperty给这个key加了一个新属性

—— WeakMap的key必须是Object类型的原因

  1. 相比Map,WeakMap持有的只是每个键值对的“弱引用”,不会额外开内存保存键值引用。这意味着在没有其他引用存在时,垃圾回收器能正确处理key指向的内存块。

—— WeakMap的key不可枚举的原因


延伸阅读

1.Object.defineProperty(obj, "prop", propDesc)和obj.prop = value的区别?

[译]JavaScript中的属性:定义和赋值的区别

2.什么是弱引用?

垃圾回收机制不考虑对该对象的引用。

也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还在该弱引用的结构中。

WeakMap不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。


参考资料

  1. https://www.zhihu.com/question/344771857
  2. https://www.jianshu.com/p/8c4ffa77b346
  3. http://es6.ruanyifeng.com/#docs/set-map#WeakSet

最新文章

  1. DevExtreme官方视频教程分享
  2. SSRS报表参数设置
  3. 解决多网卡SNMP获取不到数据的问题
  4. August 5th, 2016, Week 32nd, Friday
  5. 用UltralSO安装CentOS 和 Ubuntu
  6. Android中Context详解 ---- 你所不知道的Context
  7. UserLogin
  8. 使用C语言获取当前系统的时间
  9. 小tip:我是如何初体验uglifyjs压缩JS的
  10. android ListView用法介绍
  11. cygwin在Windows8.1中设置ssh的问题解决
  12. 使用ANR-WatchDog来检測ANR
  13. VS2012下基于Glut OpenGL glEdgeFlag示例程序:
  14. LightOJ 1234 Harmonic Number 调和级数部分和
  15. devexpress显示缓冲滚动条与实现类似QQ消息推送效果
  16. java多线程之内存可见性-synchronized、volatile
  17. JS继承以及继承的几种实现方式总结
  18. Jmeter上传附件EXCEL
  19. Python网络编程之Socket的简单实现
  20. Django-Oscar小记:如何使用高版本Django开发网页的SEO模块

热门文章

  1. 拼写单词[哈希表]----leetcode周赛150_1001
  2. EOS源码分析:transaction的一生
  3. Springboot整合html 报java.lang.IllegalArgumentException: Root element name cannot be null
  4. spring security中@PreAuthorize注解的使用
  5. LSTM 反向传播算法
  6. 【入门】广电行业DNS、DHCP解决方案详解(一)——历史及现状篇
  7. js获取Cookie,获取url参数
  8. NLP(十九) 双向LSTM情感分类模型
  9. vmware12中安装MAC OS X 10.10
  10. POJ-3169 Layout (差分约束+SPFA)