JavaScript GC

1.垃圾回收算法

垃圾:无法再被访问的对象或内存空间
延迟:指平均每次垃圾回收开始到结束需要的时间。
吞吐量:指平均一定时间内能回收多少内存,内存多少这个概念非常广泛,可以指多少个对象,也可以指多少字节的空间,具体的应该看指标应需求而异。
根节点:如全局变量上的对对象的引用、栈上对对象的引用等用户一定能够访问到的地址,是寻找活对象的入口。

下面简单地介绍引用计数、Mark-Sweep、Mark-Copy、Mark-Compact四种垃圾回收算法

1.1 引用计数

这是最初级的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。我们可以为每个对象都增加一个计数器,来记录对这个对象的引用数量,当引用计数归零时,这个对象变成了垃圾

引用计数的优点如下:

(1)内存释放及时,当一个对象死亡时其占用的内存马上被释放
(2)延迟低,内存释放的时间均匀地分布在各个时间段

缺点如下:

(1)每个对象需要附带一个计数字段的空间
(2)引用复制和销毁时需要对改变计数字段,这可能涉及到相对昂贵的原子操作
(3)无法处理循环引用,比如两个对象互相引用对方的情况

进阶话题:当一个大对象的引用归零时,常常会导致一大批的对象引用归零,这种成批释放的情况非常常见,会导致垃圾回收的延迟上升以及可能占用大量栈空间去递归释放循环引用可以通过一些算法检测到,也可以在适当时刻使用其他垃圾回收算法来释放引用计数器的更新是存在冗余的,即一大部分的引用计数的更新是可以被消除的

1.2 标记清除 Mark-Sweep

除去引用计数,Mark-Sweep是另一个思考方向。它分为标记和清除两个阶段。当垃圾回收被触发时,运行时从有限的根节点(在Javascript里,根是全局对象)出发,对所有能够到达的对象进行标记(一般为深度优先搜索),然后再遍历整个堆,清除所有未被标记的对象。

一般认为其优点有:

(1)相比引用计数很难处理循环引用,Mark-Sweep算法总能找到所有无法被引用的对象
(2)由于垃圾总被一起批量回收,可能可以提高内存回收的吞吐
(3)这个算法实现起来简单

缺点如下:

(1)每个对象需要附带至少一个比特作为标记的空间
(2)由于Mark阶段需要在整个堆上随机遍历,对CPU缓存不友好
(3)算法的性能与堆的大小相关,当堆非常大,而单次回收对象数量有限时,性能被严重拖累
(4)垃圾回收的延迟较高,会使用户代码完全停止一段时间
(5)出现内存不连续的状态

进阶话题:增量标记,即通过对算法一定的修改,Mark阶段可以与用户程序交替执行直到标记阶段完成,以减少垃圾回收算法的延迟。

1.3 标记复制 Mark-Copy

Mark-Copy将堆内存一分为二,一个处于使用状态,一个处于闲置状态。当开始垃圾回收时,会检查使用状态的内存块,把存活的对象复制到闲置状态的内存块,完成复制后,两个内存空间交换角色。

相较于Mark-Sweep,其优点有:

(1)在回收垃圾的同时也整理内存,避免了内存碎片化的问题
(2)非侵入式的算法,不需要对象上的字段(理想是美好的,但现实往往不是)
(3)算法的执行时间仅与活对象的数量有关,不需要扫描整个堆
(4)分配对象时不需要寻找空闲空间,因为其总在当前使用的堆的末尾

缺点如下:

(1)回收时需要进行大量的内存拷贝
(2)内存利用率低,维护了两个堆,却只用了一半的空间

进阶话题:
通过分块的方式维护N个堆,以提高内存利用率
对活对象进行分代维护

1.4 标记整理 Mark-Compact

注意Mark-Copy算法需要维护一个额外的堆来作为拷贝活对象的容器。标记整理和标记清除的差别在于对象标记死亡后,在整理内存的过程中,将活着的对象往一端移动,移动完成后,直接清理边界外的内存。

可以说Mark-Compact是Mark-Copy和Mark-Sweep算法的一种整合,其优缺点也只是前两种算法各取部分。

标记清除,标记复制,标记整理特点

(1)标记清除只复制活着的对象,用空间换取时间,速度最快
(2)标记复制只清除死亡的对象
(3)标记整理是两者的整合,速度最慢


2.V8 内存管理和垃圾回收机制

不同的引擎有不同的GC实现方式。这里就介绍V8 内存管理和垃圾回收机制

新生代和老生代

V8 将内存堆区分为两类:新生代内存空间和老生代内存空间,新生代内存空间主要用来存放存活时间较短的对象,老生代内存空间主要用来存放存活时间较长的对象。对于垃圾回收,新生代和老生代有各自不同的策略。

new_old_generation.jpg

新生代主要使用Scavenge垃圾回收算法进行管理,主要实现是Cheney算法,将内存平均分为两块,使用空间叫From,闲置空间叫To,新对象都先分配到From空间中,在空间快要占满时将存活对象复制到To空间中,然后清空From的内存空间,此时,调换From空间和To空间,继续进行内存分配,当满足那两个条件时对象会从新生代晋升到老生代。也就是上面提到的标记复制式的算法

老生代主要采用Mark-Sweep和Mark-Compact算法,一个是标记清除,一个是标记整理。两者不同的地方是,Mark-Sweep在垃圾回收后会产生碎片内存,而Mark-Compact在清除前会进行一步整理,将存活对象向一侧移动,随后清空边界的另一侧内存,这样空闲的内存都是连续的,但是带来的问题就是速度会慢一些。在V8中,老生代是Mark-Sweep和Mark-Compact两者共同进行管理的。由于Mark-Conpact需要移动对象,所以它的执行速度不可能很快,在取舍上,V8主要使用Mark-Sweep,在空间不足以对从新生代中晋升过来的对象进行分配时,才使用Mark-Compact。


3.javascript 内存泄露

3.1 全局变量引起的内存泄漏
3.2 闭包引起的内存泄漏
3.3 dom清空或删除时,事件未清除导致的内存泄漏
3.4 子元素存在引用引起的内存泄漏
detached-nodes.gif
  • 黄色是指直接被 js变量所引用,在内存里
  • 红色是指间接被 js变量所引用,如上图,refB 被 refA 间接引用,导致即使 refB 变量被清空,也是不会被回收的
  • 子元素 refB 由于 parentNode 的间接引用,只要它不被删除,它所有的父元素(图中红色部分)都不会被删除

参考

深入浅出nodeJs p111-119
聊聊V8引擎的垃圾回收
JavaScript常见的内存泄漏原因

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • JVM架构 当一个程序启动之前,它的class会被类装载器装入方法区(Permanent区),执行引擎读取方法区的...
    cocohaifang阅读 1,576评论 0 7
  • 原文阅读 前言 这段时间懈怠了,罪过! 最近看到有同事也开始用上了微信公众号写博客了,挺好的~给他们点赞,这博客我...
    码农戏码阅读 5,878评论 2 31
  • 第一章 简介 J2SE平台的一大优势是它的自动化内存管理,避免了开发者去面对内存管理的复杂性。 本文以Sun J2...
    tianyiliusha阅读 883评论 0 1
  • 本文由作者自行翻译,未经作者授权,不得随意转发。后续作者会陆续发布一系列关于JVM内存管理的文章,敬请期待。 1、...
    猿学堂阅读 1,301评论 0 50
  • 今天看了一下关于垃圾回收的知识,来总结一下~我们知道,JavaScript之所以能在浏览器环境和NodeJS环境运...
    Yixi_Li阅读 589评论 0 1