WeakMap 本身释放,而 keyObject 没有释放的情况下,value 会释放吗?
博客园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
里用的就是这个 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个特点
- 属性不可枚举
- 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);
},
...
};
- weakmap.set(key, val)事实上是直接通过Object.defineProperty给这个key加了一个新属性
—— WeakMap的key必须是Object类型的原因
- 相比Map,WeakMap持有的只是每个键值对的“弱引用”,不会额外开内存保存键值引用。这意味着在没有其他引用存在时,垃圾回收器能正确处理key指向的内存块。
—— WeakMap的key不可枚举的原因
延伸阅读
1.Object.defineProperty(obj, "prop", propDesc)和obj.prop = value的区别?
2.什么是弱引用?
垃圾回收机制不考虑对该对象的引用。
也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还在该弱引用的结构中。
WeakMap不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。
参考资料
- https://www.zhihu.com/question/344771857
- https://www.jianshu.com/p/8c4ffa77b346
- http://es6.ruanyifeng.com/#docs/set-map#WeakSet
WeakMap 本身释放,而 keyObject 没有释放的情况下,value 会释放吗?的更多相关文章
- Linux 不杀进程的情况下,如何释放磁盘资源
最近项目组人员反馈一个问题:即磁盘空间满了,但是并没看到有什么文件占用空间: [root@xxxx home]# df -h Filesystem Size Used Avail Use% Mount ...
- java 哪些情况下会使对象锁释放
Java_多线程_锁释放 问:Java多线程运行环境中,在哪些情况下会使对象锁释放?答:由于等待一个锁的线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的 ...
- Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载
Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...
- 鸿蒙开发板外设控制 之 实现按键“按下事件”和“释放事件”的通用框架(V0.0.1)
在帖子 <鸿蒙开发板外设控制>直播图文版(2020.10.28) 中我们提到过:"开发板上的按键也可以看作一种 GPIO 外设." 因此,要捕捉按键的状态(按下或释放) ...
- 使用QFileInfo类获取文件信息(在NTFS文件系统上,出于性能考虑,文件的所有权和权限检查在默认情况下是被禁用的,通过qt_ntfs_permission_lookup开启和操作。absolutePath()必须查询文件系统。而path()函数,可以直接作用于文件名本身,所以,path() 函数的运行会更快)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Amnes1a/article/details/65444966QFileInfo类为我们提供了系统无 ...
- 关于QSocket的释放的一个需要注意的情况(必须先断开连接)
最近在用QtNetwork编写服务器程序进行TCP/IP通信,大体过程如下: 1. 创建一个QTcpServer实例,监听目标IP和端口: 2. 一旦监听到有连接,获取和客户端之间的socket: 3 ...
- C#编程语言及.NET 平台快速入门指南
github: https://github.com/mfjiang e-mail: hamlet.jiang@live.com ⼀.C#,CLR,IL,JIT概念 以及 .NET 家族 (⼀)基 ...
- C#,CLR,IL,JIT概念 以及 .NET 家族
C#,CLR,IL,JIT概念 以及 .NET 家族 Monitor 类通过向单个线程授予对象锁来控制对对象的访问.对象锁提供限制访问代码块(通常称为临界区)的能⼒.当 ⼀个线程拥有对象的锁时,其 ...
- C# Form.Close 的释放问题
今天使用From窗口Close后,发现From的资源还存在,并没有释放资源,只有在程序关闭的时候才去释放. Form1:button按钮 private void button1_Click(obje ...
随机推荐
- 996工作制?不如花点时间学知识!北栀暗影教你如何用WordPress搭建专业网站
很多70后.80后小时候都看过这样一部动画片-<半夜鸡叫>.讲的是地主"周扒皮"为了长工们能多干些活,半夜三更起来学鸡叫让长工劳动(卖身契上规定:鸡叫就得起床干活劳动) ...
- .net软件开发脚本规范-SQL脚本标准
一. SQL脚本标准 各文件夹存放的脚本说明 存储过程:除“基础_”开头的所有存储过程,包含新增.修改.删除.列表.提交.审核. 基础数据:“基础_”开头的存储过程,用于下拉列表的数据加载公共方法. ...
- oracle 正则表达的使用
最近遇到有个项目,需要根据文件存储的根目录地址来判断是在云端获取,还是本地获取, 先看下具体有几个不同的根目录: , , 'i') from pmc.designmaterial d 去重关键字:di ...
- 实现API管理系统的几个重要关键词
管理API的需求源自于Web API开展业务.从2006年开始,然后逐渐成熟,并在2016年之前进入市场.无论是通过代理现有API的管理网关.本身作为用于部署API本身的网关的一部分,还是作为连接层在 ...
- 对已经存在的hbase表修改压缩方式
业务上可能会遇到这种情况,在最初创建hbase表时候,未指定压缩方式,当数据导入之后,由rowkey带来的数据膨胀导致hdfs上的数据大小远远大于原始数据大小.所以这时候可能就不得不考虑使用压缩,但是 ...
- springboot的异步调用
package com.handsight.platform.fras.aapp; import java.util.Locale; import org.slf4j.Logger; import o ...
- springboot中springAOP的使用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring- ...
- 使用Sigar做后台服务器管理时,遇到的linux上的问题
首先是线下猛如虎,线上惨不忍赌........ 问题的出处是: function change() { /*获取cpu*/ $.ajax({ url: "http://localhost:8 ...
- 学习 Object-C: 简史
对于一门语言的历史,我认为写一本书可能都不为过,关键是看你如何介绍和表达.当然每一个人的理解也大相径庭.本文阐述也仅仅只是冰山一角,如果需要深入了解,自己可能需要多花费一些心思. 这里也不会给大家说太 ...
- Java基础之抽象类与接口
Java基础之抽象类与接口 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的时候 ...