JavaScript 垃圾回收机制

前言

我们知道,JavaScript 中的变量分为两种:基本类型和引用类型。基本类型的值存储在栈内存,引用类型的值存储于栈内存和堆内存,栈内存中保存的是堆内存地址,地址指向堆内存中保存着的具体的值。栈内存中的变量值使用完之后会自动出栈被立即回收,但是堆内存中的值则需要某种策略或手动回收。
JavaScript 自带一套内存管理引擎来进行内存分配以及垃圾回收,那么为了更好的开发和维护高性能的 JavaScript 代码,我们需要对垃圾回收机制进行一些了解。
下面我们从以下几个方面来了解垃圾回收机制

  • 什么是垃圾回收
  • 垃圾是怎么产生的
  • 垃圾回收机制

什么是垃圾回收

垃圾回收机制的原理即找到不再使用的变量,释放其内存,因此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性地执行这已操作。

垃圾是怎么产生的

当一个对象没有任何变量或属性对它进行引用时,意味着我们无法在操作该对象了,这种对象就是所谓的"垃圾",此时就需要进行垃圾回收,如果不进行清理,内存占用越来越高,就会影响性能,甚至会导致进程崩溃。
比如:

let obj = [ 'a', 'b', 'c' ]
obj = {
  name: 'abc'
}

在 JavaScript 中,引用类型的数据保留在堆内存中,栈内存中会保留一个地址,这个地址即为堆内存中保存的值。
上面先声明了一个变量,为一个数组,之后,我们把这个变量重新赋值,那么之前的引用关系就没有了,此时,之前的那个数组就会失去引用关系,也就是我们无法在操作它了,它就变成了 "垃圾",等待被回收。

垃圾回收机制

最常见的垃圾回收机制有两种:

  1. 标记清除
  2. 引用计数

标记清除(Mark-Sweep)

标记清除,简单来说,就是使用某种方法,将不再使用的变量,也就是无用变量标记出来,等待垃圾收集器回收,释放内存。
那么,垃圾收集器是如何标记无用变量呢,这里,我们先了解一个概念——可达性。

可达性

可达性,指的是变量从"根"出发,经过一层或多层可以被访问到。即一个变量从"根"出发,可以被访问到,那么它就是"可达"的,垃圾回收器将这些"可达"的变量视为有用变量,反之则视为无用变量,无用变量会被打上标记,便于之后回收。
在 JavaScript 中,有一些基本的固有可达值,如:

  1. 本地函数的局部变量和参数
  2. 当前嵌套调用链上的其他函数的变量和参数
  3. 全局变量
  4. 一些其他的内部的值

举一个简单的例子:

let user = {
  name: 'Avery'
}
可达性.png

这里是一个全局变量 user 引用了对象,当我们把 user 重写,那么这个引用就没有了,没有了引用就变成了不可达的,就会被回收


不可达.png

了解了可达性,我们就来看下垃圾回收器是如何进行标记的吧,各个浏览器的具体实现不太相同,其运行机制如下:

  • 变量进入上下文,会被加上标记,证明其存在于该上下文
  • 将所有在上下文的变量以及上下文中被访问引用的变量标记去掉,表明这些变量活跃
  • 之后再被加上标记的变量为准备删除的变量,因为上下文中已访问不到它们了
  • 执行内存清理,销毁所有带标记的非活跃值并收回之前被占用的内存

标记清除有一个缺点就是-内存碎片,因为标记清除,在清除之后,剩余内存的位置是不变的,所以会导致空闲的内存空间是不连续的,大小不同的碎片。
想要解决这个缺点,就需要标记整理,它会在标记结束后,将不需要清理的对象移至内存的一端,最后清理掉边界的内存。

引用计数(Reference Counting)

引用计数,把"对象是否不再需要"简化定义为"对象有没有其他对象引用到它",即该对象没有被任何对象或变量引用(零引用),就会被垃圾回收机制回收,其运行机制如下:

  • 当声明了一个变量,并赋予它一个引用的值时,该值的引用次数 +1
  • 当同一个值被赋值给另一个变量的时候,引用次数 +1
  • 当该变量被另一个值覆盖的时候,引用次数 -1
  • 当引用次数为 0 的时候,就会被内存回收

引用计数有一个最大的问题,就是循环引用,如下:

function test () {
  let a = {}
  let b = {}
  a.c = b
  b.c = a
}

如上,两个都互相引用了,引用计数不为 0 ,所以无法被回收,这样就会造成内存泄漏。

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

推荐阅读更多精彩内容