iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >JavaScript垃圾回收机制原理总结深入探究
  • 717
分享到

JavaScript垃圾回收机制原理总结深入探究

JavaScript垃圾回收JS垃圾回收机制 2022-11-13 18:11:20 717人浏览 泡泡鱼
摘要

目录1. 垃圾为何要产生并回收2. 垃圾回收机制2.1 标记清除法2.2 引用计数法3. V8对垃圾回收机制的优化——分代式垃圾回收机制3.1 新生代与老生代

1. 垃圾为何要产生并回收

当我们写代码时创建一个基本类型、对象、函数等,都是需要占用内存的,javascript基本数据类型存储在栈内存中,引用数据类型存储在堆内存中,但是引用数据类型会在栈内存中存储一个实际对象的引用。

比如说我们创建了一个person对象,然后将person对象重新赋值:

var person = {
    name: "橘猫吃不胖",
    age: 2
}
person = [1, 2, 3];
console.log(person); // [ 1, 2, 3 ]

那么原本堆内存给person对象开辟了一个空间来存放,栈内存中存放了该引用的地址,但是在下一步中,person对象成为了一个数组,也就是说引用地址从原来的对象变成了数组,原来的引用关系就没有了,那么这时原来的对象在堆内存中就会成为一个垃圾。

产生的垃圾如果很多,而且一直不清理,堆积起来,就会影响系统的性能,甚至可能造成系统崩溃。

2. 垃圾回收机制

JavaScript中主要的内存管理概念是可达性。

那什么是可达性呢,比如说定义一个对象:

let person = {
    name: "橘猫吃不胖",
    age: 2
}
console.log(person.name, person.age); // 橘猫吃不胖 2

person引用了这个对象,通过person.name可以获取到“橘猫吃不胖”的值,通过person.age可以获取到2,那么这时就可以认为“橘猫吃不胖”和2是可达的。

person = null;
console.log(person.name, person.age); // TypeError: Cannot read properties of null (reading 'name')

如果将person设置为null,那么这两个值就没法获得了,它们就是不可达的,这时JavaScript垃圾回收机制就会自动从内存中将其清除。

那么JavaScript的垃圾回收就是定期找出这些不可达的对象,然后将其释放。那么找出这些不可达的对象有两种常用的策略:

  • 标记清除法
  • 引用计数法

2.1 标记清除法

标记清除法分为标记和清除两个阶段,标记阶段需要从根节点遍历内存中的所有对象,并为可达的对象做上标记,清除阶段则把没有标记的对象(非可达对象)销毁。

标记清除法的优点就是实现简单。

它的缺点有两个,首先是内存碎片化。这是因为清理掉垃圾之后,未被清除的对象内存位置是不变的,而被清除掉的内存穿插在未被清除的对象中,导致了内存碎片化。

第二个缺点是内存分配速度慢。由于空闲内存不是一整块,假设新对象需要的内存是size,那么需要对空闲内存进行一次单向遍历,找出大于等于size的内存才能为其分配。

标记清除算法改进—— 标记整理算法

标记清除算法的缺点主要在于内存清理之后剩余的内存位置不变而导致内存碎片化,因此可以使用标记整理算法改进。

标记整理算法的标记阶段与标记清除算法相同,都是从根节点遍历内存中的所有对象,为可达的对象打上一个标记。但是在标记结束后,标记整理算法将这些可达的对象移向内存的一端,然后清理掉边界的内存。

2.2 引用计数法

引用计数法主要记录对象有没有被其他对象引用,如果没有被引用,它将被垃圾回收机制回收。它的策略是跟踪记录每个变量值被使用的次数,当变量值引用次数为0时,垃圾回收机制就会把它清理掉。

示例代码如下:

let person = { name: "橘猫吃不胖" }; // { name: "橘猫吃不胖" } 引用次数为1
let person1 = person; // { name: "橘猫吃不胖" } 引用次数为2
person = null; // { name: "橘猫吃不胖" } 的引用次数为1
person1 = null; // { name: "橘猫吃不胖" } 的引用次数为0

引用计数法的优点是可以实现立即进行垃圾回收。当引用计数在引用值为0时,立即进行垃圾回收,这样可以达到立刻垃圾回收的效果。

它的缺点也有两个,首先它需要一个计数器,这个计数器可能要占据很大的位置,因为我们无法知道被引用数量的多少。

第二个缺点是无法解决当出现循环引用时无法回收的问题。例如a引用了bb也引用了a,两个对象相互引用,引用计数不为0,因此无法进行内存清理,如下所示:

let a = { name: "橘猫吃不胖" };
let b = { age: 2 };
a.age = b;
b.name = a;

3. V8对垃圾回收机制的优化——分代式垃圾回收机制

目前大多数浏览器都是基于标记清除算法,V8进行了一些优化加工处理,采用分代式垃圾回收机制。

3.1 新生代与老生代

原本的垃圾回收机制在每次回收时都要检查内存中所有的对象,这样的话,一些大、老、存活时间长的对象与新、小、存活时间短的对象检查频率相同,但是前者并不需要频繁进行清理,因此采用分代式垃圾回收机制。

V8中将堆内存分为新生代和老生代两区域,采用不同的垃圾回收策略进行回收。新生代的对象为存活时间较短的对象,通常只支持1~8M的容量,老生代的对象为存活时间较长或常驻内存的对象,容量通常比较大,V8整个堆内存的大小就等于新生代加上老生代的内存。

3.2 新生代的垃圾回收

新生代垃圾回收策略中,将堆内存一分为二,一个是处于使用状态的使用区,一个是处于闲置状态的空闲区。

新加入的对象都会存放到使用区,当使用区快满时,就需要执行一次垃圾清理操作,即新生代垃圾回收机制会对使用区中的活动对象(不需要被清理的对象)做标记,标记完成之后将这些活动对象复制到空闲区并进行排序(避免内存碎片化),然后将使用区清空,原来的空闲区变为使用区,原来的使用区变为空闲区。

当一个对象经过多次复制后依然存活,它将会被认为是生命周期较长的对象,会被移动到老生代的内存中,或者一个对象被复制到空闲区时,空闲区占用空间超过了25%,那么该对象也会进入老生代内存中。

新生代回收策略——并行回收

JavaScript是单线程的语言,当执行垃圾回收时,就会阻塞JavaScript脚本的执行,垃圾回收结束后再继续JavaScript脚本执行,这种情况叫做全停顿(Stop-The-World)。

如果执行一次垃圾回收需要100ms,那么脚本执行就得暂停100ms,如果执行垃圾回收的时间过长,那么就会造成页面卡顿,带来不好的用户体验。对于这样的情况,可以采用并行回收的策略。

并行回收指的是在主线程进行垃圾回收时,同时开启多个辅助线程一起执行垃圾回收。比如说一项任务一个人需要30天才能完成,那么如果安排两个人甚至多个人,可能10来天甚至更短的时间就完成了。实现并行回收可以大大降低垃圾回收的暂停时间。

新生代对象空间就采用并行策略,在执行垃圾回收的过程中,会启动了多个线程来负责新生代中的垃圾清理操作,这些线程同时将对象空间中的数据移动到空闲区域,这个过程中由于数据地址会发生改变,所以还需要同步更新引用这些对象的指针,此即并行回收。

3.3 老生代的垃圾回收

老生代的垃圾回收操作主要就是标记清除算法的步骤了,在标记阶段标记所有的可达对象,清除阶段清除掉未被标记的对象。又由于该算法会出现内存碎片的问题,因此会使用标记整理算法来优化这个过程。

老生代回收策略——增量标记与惰性清理 ①增量标记

增量就是将一次标记的过程,分成了许多次,每执行完一次就让应用逻辑执行一会儿,这样交替多次后完成垃圾回收。但是这会随之而来新的问题,首先是如何暂停每次标记去执行JavaScript代码,还有如果标记好的对象在执行js中改变了状态成为了可达或者不可达对象怎么办,V8对这两个问题对应的解决方案分别是三色标记法与写屏障。

a.三色标记法

三色标记法使用三种颜色白、灰、黑来标记对象的状态。白色表示初始状态,黑色表示已检查状态,灰色表示待检查状态。

它的过程为:

1、将所有的对象设置为白色,然后从root对象出发,将所有可以访问的对象标记为灰色,并用一个数组缓存起来;

2、遍历该数组,每次都把要遍历的对象标记为黑色并移出,并且把他的相邻节点都涂成灰色,并放入队列,直到队列为空

3、继续检查是否有灰色对象,如果有继续放入队列然后循环,直到所有的可访问对象都变成黑色

采用三色标记法后,程序在恢复执行时可以直接判断当前内存中有没有灰色节点,如果有灰色节点,那么从灰色节点开始继续执行,如果没有,直接进入垃圾清理阶段。

b.写屏障

写屏障可以解决第二个问题,如果执行任务程序时内存中标记好的对象引用关系被修改了,比如说黑色对象引用了白色对象,那么它就会将白色对象改成灰色对象,这样就可以保证下一次标记时可以正常进行。

②惰性清理

增量标记完成后,就开始清除垃圾。如果当前的可用内存可以支持快速的执行代码,就没必要立即清理内存,而且清理时没必要一次性清理完,可以按需清理。

优点:大大减少了主线程停顿的时间,让用户与浏览器交互的过程变得更加流畅

缺点:并没有减少主线程的总暂停的时间,甚至会略微增加

老生代回收策略——并发回收

并发回收指的是主线程在执行JavaScript的过程中,辅助线程能够在后台,完成执行垃圾回收的操作,辅助线程在执行垃圾回收的时候,主线程也可以自由执行

垃圾回收机制多次阅读之后,我受益匪浅,因此写该文章记录一下~

到此这篇关于JavaScript垃圾回收机制原理总结深入探究的文章就介绍到这了,更多相关JavaScript垃圾回收内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: JavaScript垃圾回收机制原理总结深入探究

本文链接: https://www.lsjlt.com/news/169768.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript垃圾回收机制原理总结深入探究
    目录1. 垃圾为何要产生并回收2. 垃圾回收机制2.1 标记清除法2.2 引用计数法3. V8对垃圾回收机制的优化——分代式垃圾回收机制3.1 新生代与老生代...
    99+
    2022-11-13
    JavaScript垃圾回收 JS垃圾回收机制
  • 深入剖析 JavaScript 垃圾回收机制
    机制 JavaScript 使用“标记-清除”垃圾回收算法: 标记阶段:垃圾回收器遍布应用程序的内存,并标记所有仍在被使用的对象。 清除阶段:垃圾回收器释放所有未标记的对象占用的内存。 垃圾回收触发器 JavaScript 垃圾回收在...
    99+
    2024-04-02
  • Go语言的垃圾回收机制探究
    Go语言作为一门开发者友好的编程语言,以其高效、简洁和强大的特性而备受称赞。其中,其垃圾回收机制是其独特之处之一,为开发者提供了方便和便利。本文将深入探讨Go语言的垃圾回收机制,探究其...
    99+
    2024-04-02
  • 深入探索Go语言垃圾回收机制的工作原理
    Go语言的垃圾回收机制采用了并发标记清除(concurrent mark and sweep)的算法,主要分为三个阶段:标记阶段、清...
    99+
    2023-10-08
    Golang
  • 深入研究Go语言的垃圾回收器管理机制
    Go语言的垃圾回收器是一种自动管理内存的机制,它负责在运行时检测和回收不再使用的内存,以避免内存泄漏和悬空指针等问题。Go语言的垃圾...
    99+
    2023-10-08
    Golang
  • 深入了解JavaScript中的垃圾回收机制
    JavaScript中的垃圾回收机制负责自动管理内存,回收不再使用的对象所占用的内存空间。在JavaScript中,开发者不需要显式地分配和释放内存,垃圾回收器会自动完成这些操作。以...
    99+
    2023-05-15
    JavaScript垃圾回收机制 JavaScript垃圾回收
  • 如何深入Java核心探秘Java垃圾回收机制
    这期内容当中小编将会给大家带来有关如何深入Java核心探秘Java垃圾回收机制,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。垃圾收集GC(Garbage Collection)是Java语言的核心技术之一...
    99+
    2023-06-17
  • .NET垃圾回收机制知识点总结
    这篇文章主要讲解了“.NET垃圾回收机制知识点总结”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“.NET垃圾回收机制知识点总结”吧! .NET资源分托管资源和非托管资源,对于托管资源,.NE...
    99+
    2023-06-17
  • Python垃圾回收机制的原理
    本篇内容介绍了“Python垃圾回收机制的原理”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  引用计数器为主  标记清除和分代回收为辅  ...
    99+
    2023-06-01
  • 分析python垃圾回收机制原理
    目录引用计数引用计数案例导致引用计数 +1 的情况导致引用计数-1 的情况循环引用导致内存泄露分代回收垃圾回收gc 模块常用函数:引用计数 Python 语言默认采用的垃圾...
    99+
    2024-04-02
  • 怎么理解JavaScript垃圾回收机制
    本篇内容介绍了“怎么理解JavaScript垃圾回收机制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!机制说明找出不再使用的变量,然后释放它...
    99+
    2023-06-25
  • JavaScript中的垃圾回收机制
    聚沙成塔·每天进步一点点 ⭐ 专栏简介⭐ JavaScript的垃圾回收机制⭐ 内存管理⭐ 引用计数⭐ 标记-清除算法⭐ 内存泄漏⭐ 性能优化⭐ 使用`delete`操作符⭐ 注意循环中的变量...
    99+
    2023-10-05
    javascript 开发语言 ecmascript
  • PHP垃圾回收机制原理分析
    这篇文章主要介绍了PHP垃圾回收机制原理分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。PHP垃圾回收机制1、每一个变量定义时都保存在一个...
    99+
    2024-04-02
  • 深入理解Go语言中的垃圾回收机制
    Go语言中的垃圾回收(GC)机制是自动进行的,开发者不需要手动管理内存。这种自动化垃圾回收机制可以帮助开发者降低内存泄漏的风险,并减...
    99+
    2023-10-08
    Golang
  • 深入浅析JS中的垃圾回收机制
    基本类型存放在栈中,引用类型存放在堆中。JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。垃圾回收策略所有垃圾回收器都需要做的任务标记空间中活动(存活)对象和非...
    99+
    2023-05-14
    javascript 垃圾回收机制
  • 深入剖析Go语言垃圾回收机制的原理与应用
    Go语言的垃圾回收机制是一种自动的内存管理机制,它通过解决内存分配和回收的问题,使得开发者无需显式地管理内存,可以更专注于业务逻辑的...
    99+
    2023-10-08
    Golang
  • javascript有垃圾回收机制gc吗
    今天小编给大家分享的是javascript有垃圾回收机制gc吗,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。javascript中有GC(垃圾回收机...
    99+
    2024-04-02
  • 详解JavaScript的垃圾回收机制
    目录为什么需要垃圾回收(GC)什么是垃圾回收垃圾产生垃圾回收策略引用计数标记循环引用引发的问题解决方法引用计数算法的优缺点标记清除算法核心思想标记清除算法优缺点标记整理算法V8引擎的...
    99+
    2024-04-02
  • 深入探讨Go语言中的垃圾回收
    Go语言作为一种现代化的编程语言,因其并发能力和简洁的语法而备受开发者推崇。然而,与其他编程语言一样,Go语言也面临着内存管理的挑战,其中垃圾回收(Garbage Collection...
    99+
    2024-04-02
  • 深入理解JVM垃圾回收算法
    目录一、垃圾标记阶段1.1、引用计数法(java没有采用)1.2、可达性分析算法二、对象的finalization机制2.1、对象是否"死亡"三、使用(MAT与JProfiler)工...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作