垃圾回收机制

GC

GC是什么

GC是Garbage Collection的缩写,中文意为垃圾回收。它是程序语言内存管理的一种自动机制。

GC主要的作用

  1. 自动释放不再使用的内存空间,避免内存泄漏。
  2. 整理内存碎片,提高内存利用率。

GC的实现一般遵循的步骤

  1. 根节点扫描:扫描根节点(全局变量),找到所有存活的对象,将其标记。
  2. 存活对象标记:从根节点开始递归扫描,将找到的所有存活对象及其关联对象标记。
  3. 回收未标记对象:扫描内存空间,回收所有未标记的对象占用的内存空间。
  4. 内存整理:将存活对象移至一端,紧凑内存布局,释放未使用内存。

常见的GC算法

  1. 引用计数(Reference Counting):给每个对象维护一个引用计数,当计数为0时回收内存。简单但无法解决循环引用问题。
  2. 标记-清除(Mark and Sweep):遍历内存标记存活对象,然后清除未标记对象。可以解决循环引用问题但会产生内存碎片。
  3. 复制收集(Copying):将内存一分为二,每次只使用其中一半。将存活对象复制到未使用内存,然后清除源内存。避免内存碎片但浪费空间。
  4. 分代收集(Generational Collection):根据对象存活周期将内存分为新生代和老生代,各自使用不同的收集算法。提高回收效率。
  5. 标记-整理(Mark and Compact):标记存活对象后,将对象移至一端,然后清除边界外内存。既解决碎片又不浪费空间。

垃圾回收策略

可达性:

JavaScript 内存管理中当对象不再被任何引用指向(访问、调用、可用)时,该对象就可以被垃圾回收,反之则存储在内存中。

JavaScript 垃圾回收机制:

主要基于标记-清除算法实现

标记-清除算法:

  1. 标记阶段:垃圾回收器会从根节点(全局变量)开始遍历对象图,查找并标记所有可达对象(活动对象)。

  2. 清除阶段:垃圾回收器会清扫内存,释放所有未标记对象(垃圾对象)占用的空间。

  3. 内存整理:将存活对象移至更紧凑的内存布局,避免内存碎片。

实现过程:

  1. 当JavaScript程序运行时,会在内存中创建各种对象。

  2. 部分对象会被存储在其他对象或全局变量中,成为可达对象。而其他对象失去引用变成垃圾对象。

  3. 当垃圾回收被触发时(一般由JS引擎触发),会暂停其他线程的执行。

  4. 垃圾回收器会从根节点开始遍历所有可达对象,并标记为活动对象。然后递归遍历活动对象的子对象标记。

  5. 所有未标记的对象会被视为垃圾对象,准备被清除。

  6. 垃圾回收器会清除垃圾对象占用的内存空间,并整理内存布局。

  7. 垃圾回收结束后,JS引擎继续执行其他任务。

此外,JavaScript还采用分代收集法对内存进行分区管理。新创建的对象多存活短暂,存放于新生代。可达对象逐渐变老,搬迁到老生代。分代回收能更高效的回收对象,减少内存碎片。当然,JS引擎也提供其他的优化手段,诸如增量并发标记、空闲列表等,不断提高内存管理效率,为最佳用户体验做支撑。

优点:

  1. 可以有效地解决循环引用问题。标记-清除算法会从根节点开始迭代标记所有可达对象,而不仅仅依赖引用计数。
  2. 实现简单,耗时短,GC停顿时间较短。标记和清除过程的时间复杂度都为O(n),所以总体来说标记-清除算法实现简单高效。

缺点:

  1. 会产生内存碎片。由于清除后会留下未使用内存空间,长期来看会使内存布局越来越碎片化,降低内存利用率。
  2. 标记和清除过程会造成较长GC停顿时间。对于一些实时性要求较高的应用来说,这个停顿时间可能无法接受。
  3. 标记过程需要递归遍历对象图,对象规模较大时,标记时间过长。标记算法时间复杂度O(n),n代表对象数量,对象过多时标记过程会十分耗时。
  4. 全堆扫描效率低下。标记-清除算法需要扫描整个内存堆区,对于大内存应用,全堆扫描的代价太大。
    注意:为了规避标记-清除法的缺点,目前的垃圾回收器一般会采用分代收集法,仅对新生代采用标记-清除算法进行快速回收。而对老生代则采用标记-整理或者增量标记算法实现更高效的回收。

引用计数算法

基本思想:

为每个对象维持一个引用计数,表示当前有多少个对象或变量引用该对象。当一个对象的引用计数变为0时,表示该对象成为不可达对象,这个对象的内存空间可以被回收。

优点:

  1. 实现简单,时间复杂度O(1)。仅需要在创建和销毁引用时递增和递减计数,性能很高。
  2. 回收速度快。一旦引用计数为0,对象内存可以立即回收,不需要像标记-清除那样需要等到下次GC周期。

缺点:

  1. 无法解决循环引用问题。两个对象相互引用,导致引用计数无法为0,发生内存泄漏。
  2. 需要额外空间存储引用计数。每次有新的引用创建时,需要找到对象并递增引用计数,这个额外操作会消耗一定性能。
  3. 回收时需要重置大量对象的引用计数。当一个包含大量子对象的父对象被销毁时,需要找到所有子对象并递减其引用计数,这也是比较耗时的操作。

引用计数算法适用的场景:

  1. 对象之间没有循环引用,或者循环引用较少的情况。
  2. 对实时性要求较高的应用,需要快速回收内存。
  3. 内存回收频率较高,但每次回收规模较小的场景。
  4. 作为其他算法(如标记-清除算法)的补充,在老生代中部分使用。
    注意: 现代浏览器会选用标记-清除算法或其优化算法(如增量标记)进行内存管理,而非纯引用计数算法。

引用计数算法+标记-清除算法:

  1. 分代收集:根据对象存活周期不同,将内存分为新生代和老生代。新生代采用引用计数法,老生代采用标记-清除法。这可以解决引用计数法无法回收循环引用对象的问题,同时发挥其在频繁回收小对象方面的优势。
  2. 定期循环检测:每隔一定时间对内存进行一次完整扫描,发现引用计数未为0的循环引用对象并进行标记。然后将这些对象的引用计数设为0,等到下次GC时进行回收。这种策略可以有效减少循环引用导致的内存泄漏。
  3. 由引用计数触发标记-清除:当引用计数法无法回收更多内存时(回收速度下降),触发一次标记-清除算法进行内存回收。这可以快速释放大块内存,避免由于引用计数法导致的频繁GC造成的性能问题。
  4. 引用计数递增时检测循环:在对象引用计数递增时,检测其是否已被其他对象引用。如果是,则说明存在循环引用,需要标记这两个对象以防止内存泄漏。这种策略可以及早发现和解决循环引用问题。
  5. 定期执行标记-清除:虽然引用计数法可以快速回收内存,但是会产生一定内存碎片。定期执行标记-清除算法可以整理内存,提高内存利用率。
    总结:引用计数法用于快速回收短期存活对象和新生代对象,发挥其快速回收的优势。而标记-清除算法用于解决循环引用问题,回收老生代对象,实现内存整理,发挥其解决碎片和循环引用的优势。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容