【图解篇】前端内存管理

前端为什么要关注内存

  • 防止占用内存过大,造成页面卡顿,甚至无响应
  • Node.js 使用 V8 引擎,内存管理对于服务端至关重要,因为服务端的持久性,内存更容易积累造成内存溢出

js 垃圾回收机制

js 使用垃圾回收机制自动管理内存,这种方式的利弊都很明显。

  • 优势: 可以大幅简化程序中都内存管理代码,减轻开发者的负担,同时也减少长时间运转造成的内存泄漏问题
  • 劣势: 意味着开发者无法掌控内存管理,我们无法强迫其进行垃圾回收,进行管理

下面简单介绍一下 js 的几种垃圾回收策略:

引用计数

主要是IE8 以下的浏览器使用,现代浏览器都弃用了这种方式,这里只做简单介绍。

基本原理就是,记录跟踪每个值被引用的次数,被引用一次被引用次数就加一,被释放就减一,为零时,就释放改值所占内存。

标记清除

主流浏览器使用垃圾回收机制。

当变量进入环境(例如,在函 数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。

而当变量离开环境时,则将其 标记为“离开环境”。 可以使用任何方式来标记变量。比如,可以通过翻转某个特殊的位来记录一个变量何时进入环境, 或者使用一个“进入环境的”变量列表及一个“离开环境的”变量列表来跟踪哪个变量发生了变化。

function test(){
    var a = 10;    //被标记"进入环境"
    var b = "hello";    //被标记"进入环境"
}
test(); // 执行完毕后之后,a和b又被标记"离开环境",被回收

说到底,如何标记变量其实并不重要,关键在于采取什么策略。 垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。

然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记 的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。

最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

环境可以理解为我们的作用域,但是全局作用域的变量只会在页面关闭才会销毁。

V8 内存控制

V8 的内存限制

在 Node 中只能使用部分内存,64位系统下约为1.4GB,32位系统下约为0.7GB,在这种限制下,将会导致 Node 无法操作大内存对象,比如将一个 2GB 的文件读入内存,即使物理内存有64 GB,也没有办法完成,这个时候我们可以使用 Buffer 类,来完成大内存文件的读取。

造成这个问题的主要原因: Node 基于 V8 构建,而 V8 的这套内存管理机制主要是在浏览器中使用,完全可以满足前端页面中的所有需求,但是在 Node 中却限制了开发者随心所欲使用大内存的想法。

V8 的垃圾回收机制

V8 的垃圾回收策略主要基于分代式垃圾回收机制。主要将内存分为新生代和老生代两代。

图片

新生代空间(Young Generaion)

特点:

  • 管理对象存活时间较短
  • 占用空间比老生代空间小很多
  • 垃圾回特别频繁

新生代空间的垃圾回收采用Scavenge 算法,其工作原理如下

  1. 将新生代空间分为两个空间,称为semispace,处于使用状态的叫做 From 空间,处于闲置的叫 To 空间,当我们分配对象时,先是在 From 空间中进行分配。
图片
  1. 开始垃圾回收时,会检查 From 空间中的存活对象,这些存活对象将被复制到 To 空间中,然后释放 From 空间中的内存。
图片
图片
  1. From 空间与 To 空间对换
图片

从上面的过程我们可以看到,Scavenge 算法是典型的牺牲空间换取时间的算法。缺点是只能使用堆内存中的一半,优点是在时间效率上有优异的表现。

老生代空间( OldGeneraion)

在新生代空间中生命周期较长的对象会被复制到老生代空间中,这个过程叫晋升。对象晋升的条件主要有两个:

  1. 对象是否经历过一次 Scavenge 回收。 对象从 From 空间复制到 To 空间时,会检查它的内存地址来判断这个对象是否已经经历过一次 Scavenge 回收。如果经历过,就直接复制到老生代空间中,而不是 To 空间。
  2. To 空间的内存使用占比是否超过 To 空间的 25%。 对象从 From 空间复制到 To 空间时,发现 To 空间的内存占比已经超过限制。因为To 空间将会变成 From空间,为了不影响后续的内存分配,会直接晋升到老生代空间中。

对于老生代空间,由于存活对象占比较大,再采用Scavenge的方式会有两个问题:

  1. 存活对象比较多,复制存活对象的效率会很低
  2. 要拆分两个 semispace 空间,比较浪费

为此,老生代中主要采用标记清除(Mark-Sweep)标记整理(Mark-Compact)相结合的方式进行垃圾回收,其工作原理如下

  • 在标记阶段遍历堆中的所有对象,并标记活着的对象,在随后的清除阶段中,只清除没有被标记的对象。标记后的示意图如下:
图片

黄色部分为标记活跃的对象,深灰色部分为标记死亡的对象。

标记清除(Mark-Sweep)最大的问题在于,清除标记死亡的对象后,内存不连续,这种碎片空间会对后续的内存分配造成问题。

  • 为了解决内存碎片的问题,标记整理(Mark-Compact)被提出来。它会在标记完成后,将存活的对象移动到一端,然后释放存活对象这一端之外的空间。
图片
图片

增量标记(Incremental Marking)

在进行上面 V8垃圾回收操作的时候,需要将应用逻辑暂停,但是由于老生代空间很大,且存活对象很多,为了避免长时间的停顿,将原本一次性完成的操作改为增量标记,即拆分为许多小“步进”,没做完一次“步进”,让应用逻辑执行一会儿,交替执行,直到垃圾回收执行完成。

参考文章:

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

推荐阅读更多精彩内容