JS 垃圾回收机制
【转自】:https://segmentfault.com/a/1190000018605776
垃圾回收
JavaScript 中的内存管理是自动执行的,而且是不可见的。我们创建基本类型、对象、函数……所有这些都需要内存。
当不再需要某样东西时会发生什么? JavaScript 引擎是如何发现并清理它?
可达性
JavaScript 中内存管理的主要概念是可达性。
简单地说,“可达性” 值就是那些以某种方式可访问或可用的值,它们被保证存储在内存中。
1. 有一组基本的固有可达值,由于显而易见的原因无法删除。例如:
- 本地函数的局部变量和参数
- 当前嵌套调用链上的其他函数的变量和参数
- 全局变量
- 还有一些其他的,内部的
这些值称为根。
2. 如果引用或引用链可以从根访问任何其他值,则认为该值是可访问的。
例如,如果局部变量中有对象,并且该对象具有引用另一个对象的属性,则该对象被视为可达性, 它引用的那些也是可以访问的,详细的例子如下。
JavaScript 引擎中有一个后台进程称为垃圾回收器,它监视所有对象,并删除那些不可访问的对象。
一个简单的例子
下面是最简单的例子:
// user 具有对象的引用 let user = { name: "John" };
这里箭头表示一个对象引用。全局变量“user”
引用对象 {name:“John”}
(为了简洁起见,我们将其命名为John)。John 的 “name”
属性存储一个基本类型,因此它被绘制在对象中。
如果 user
的值被覆盖,则引用丢失:
user = null;
现在 John 变成不可达的状态,没有办法访问它,没有对它的引用。垃圾回收器将丢弃 John 数据并释放内存。
两个引用
现在让我们假设我们将引用从 user
复制到 admin
:
// user具有对象的引用 let user = { name: "John" }; let admin = user;
现在如果我们做同样的事情:
user = null;
该对象仍然可以通过 admin
全局变量访问,所以它在内存中。如果我们也覆盖admin
,那么它可以被释放。
相互关联的对象
现在来看一个更复杂的例子, family 对象:
function marry (man, woman) { woman.husban = man; man.wife = woman; return { father: man, mother: woman } } let family = marry({ name: "John" }, { name: "Ann" })
函数 marry
通过给两个对象彼此提供引用来“联姻”它们,并返回一个包含两个对象的新对象。
产生的内存结构:
到目前为止,所有对象都是可访问的。
现在让我们删除两个引用:
delete family.father; delete family.mother.husband;
仅仅删除这两个引用中的一个是不够的,因为所有对象仍然是可访问的。
但是如果我们把这两个都删除,那么我们可以看到 John 不再有传入的引用:
输出引用无关紧要。只有传入的对象才能使对象可访问,因此,John 现在是不可访问的,并将从内存中删除所有不可访问的数据。
垃圾回收之后:
无法访问的数据块
有可能整个相互连接的对象变得不可访问并从内存中删除。
源对象与上面的相同。然后:
family = null;
内存中的图片变成:
这个例子说明了可达性的概念是多么重要。
很明显,John和Ann仍然链接在一起,都有传入的引用。但这还不够。
“family”对象已经从根上断开了链接,不再有对它的引用,因此下面的整个块变得不可到达,并将被删除。
内部算法
基本的垃圾回收算法称为“标记-清除”,定期执行以下“垃圾回收”步骤:
- 垃圾回收器获取根并“标记”(记住)它们。
- 然后它访问并“标记”所有来自它们的引用。
- 然后它访问标记的对象并标记它们的引用。所有被访问的对象都被记住,以便以后不再访问同一个对象两次。
- 以此类推,直到有未访问的引用(可以从根访问)为止。
- 除标记的对象外,所有对象都被删除。
例如,对象结构如下:
我们可以清楚地看到右边有一个“不可到达的块”。现在让我们看看“标记并清除”垃圾回收器如何处理它。
第一步标记根
然后标记他们的引用
以及子孙代的引用:
现在进程中不能访问的对象被认为是不可访问的,将被删除:
这就是垃圾收集的工作原理。JavaScript引擎应用了许多优化,使其运行得更快,并且不影响执行。
一些优化:
- 分代回收——对象分为两组:“新对象”和“旧对象”。许多对象出现,完成它们的工作并迅速结 ,它们很快就会被清理干净。那些活得足够久的对象,会变“老”,并且很少接受检查。
- 增量回收——如果有很多对象,并且我们试图一次遍历并标记整个对象集,那么可能会花费一些时间,并在执行中会有一定的延迟。因此,引擎试图将垃圾回收分解为多个部分。然后,各个部分分别执行。这需要额外的标记来跟踪变化,这样有很多微小的延迟,而不是很大的延迟。
- 空闲时间收集——垃圾回收器只在 CPU 空闲时运行,以减少对执行的可能影响。
JS 垃圾回收机制的更多相关文章
- 前端面试:谈谈 JS 垃圾回收机制
摘要: 不是每个人都回答的出来... 最近看到一些面试的回顾,不少有被面试官问到谈谈JS 垃圾回收机制,说实话,面试官会问这个问题,说明他最近看到一些关于 JS 垃圾回收机制的相关的文章,为了 B 格 ...
- python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除
js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...
- 谈谈 JS 垃圾回收机制
谈谈 JS 垃圾回收机制 JS内存泄漏与垃圾回收机制 https://javascript.info/garbage-collection
- 浅尝js垃圾回收机制
局部作用域内的变量,在函数执行结束之后就会被js的垃圾回收机制销毁 为什么要销毁局部变量? => 为了释放内存 js垃圾回收机制何时会销毁局部变量 : 如果局部变量无法再得到访问,就会被 ...
- 闭包内的微观世界和js垃圾回收机制
一.什么是闭包? 官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述的太学术.其实这句话 ...
- js 垃圾回收机制和引起内存泄漏的操作
垃圾回收机制 JS中最常见的垃圾回收方式是标记清除. 工作原理:是当变量进入环境时,将这个变量标记为“进入环境”.当变量离开环境时,则将其标记为“离开环境”.标记“离开环境”的就回收内存. 工作流程: ...
- 理解闭包的微观世界和JS垃圾回收机制
function a() { ; function b() { alert(++i); } return b; } var c = a(); c(); 一.闭包的微观世界 如果要更加深入的了解闭包以及 ...
- v8垃圾回收和js垃圾回收机制
垃圾回收器是一把十足的双刃剑.好处是简化程序的内存管理,内存管理无需程序员来操作,由此也减少了长时间运转的程序的内存泄漏.然而无法预期的停顿,影响了交互体验.本文从 V8 (node.js runti ...
- 关于JS垃圾回收机制
一.垃圾回收机制的必要性 由于字符串.对象和数组没有固定大小,所以当它们的大小已知时,才能对它们进行动态的存储分配.JavaScript程序每次创建字符串.数组或对象时,解释器都必须分配内存来存储那个 ...
- js垃圾回收机制
垃圾回收机制,简称GC(garbage collection),会定期(周期性)地回收那些不再使用的变量,然后释放其内存. 而内存占用的情况有很多: 1.变量 2.字面量对象声明:var obj = ...
随机推荐
- 使用yum update更新文件系统时不更新内核的方法
CentOS使用yum update更新时不升级内核 cp /etc/yum.conf /etc/yum.confbak 方法一.修改yum的配置文件 vi /etc/yum.conf 在[m ...
- Golang - 并发编程
目录 Golang - 并发编程 1. 并行和并发 2. go语言并发优势 3. goroutine是什么 4. 创建goroutine 5. runtime包 6. channel是什么 7. ch ...
- MYSQL更换密码
MYSQL5.7以下版本的数据库密码使用的是 mysql这个数据库里的user表的password这个字段, 修改密码只需: 1.update MySQL.user set password=pass ...
- 【Zoj 4061】Magic Multiplication
[链接] 我是链接,点我呀:) [题意] [题解] /* for a[1] from 1~9 1*1=1 2*1=2 3*1=3 1*2=2 2*2=4 3*2=6 1*3=3 2*3=6 3*3=9 ...
- lucene_03_索引的增删改查
lucene索引的添加见 http://www.cnblogs.com/getchen/p/8615276.html 入门代码. 公共代码 public <T extends Query> ...
- spring boot @Transactional事物处理
spring boot 添加事物使用 @Transactional注解 简单使用 在启动类上方添加 @EnableTransactionManagement注解 使用时直接在类或者方法上使用 @Tra ...
- 如何用PYTHON的CGIHTTPSERVER模块模拟POST请求?
这次又要逼真一点点,可以弄POST请求啦. 在WEB根目录下新建cgi-bin目录(据说是规模要求),然后运行命令: python -m CGIHTTPServer CGI-BIN目录下,form.p ...
- 反射常用API
反射所有功能都是通过class API来实现的 class常用API有: 1.class.GETINTERFACES():获得这个类实现的接口. 2.class.getMethods() Method ...
- SecureCRT 会话丢失的处理办法
SecureCRT 会话丢失的处理办法 在SecureCRT中已经有了70多个session,密码都记忆了,当然有些失效的也没有删除: 某一天,打开SecureCRT之后,发现session都没有了, ...
- [Javascript] Understand common misconceptions about ES6's const keyword
Values assigned with let and const are seen everywhere in JavaScript. It's become common to hear the ...