V8垃圾回收

article/2025/11/10 6:21:31

在这里插入图片描述

来自李兵老师的《浏览器工作原理与实践》,太赞了

垃圾回收

    • 内存空间
    • 栈空间和堆空间
    • 不同语言的垃圾回收策略
    • 调用栈中的数据是如何回收的
    • 堆中的数据是如何回收的
    • 副垃圾回收器
    • 主垃圾回收器
    • 总结

在我们说V8垃圾回收之前,先讲讲 数据是如何存储的?

我们都知道JavaScript是一种弱语言,动态的语言。那这些特点意味着什么呢?
弱语言,意味着你不需要告诉JavaScript引擎这个或那个变量是什么数据类型,JavaScript引擎在运行代码的时候会自己计算出来;
动态,意味着你可以使用同一个变量保存不同类型的数据。

那JavaScript是有多少种数据类型。其实JavaScript中的数据类型一共有8种,分别是:
在这里插入图片描述
其中这八种数据中又分了 原始类型引用类型。除了Object是引用类型,其他的都是原始类型。那为什么会给这些数据划分不同的类型,是因为它们在内存中存放的位置不一样,到底是这么个不一样法,我们接下来看看。

内存空间

要理解JavaScript在运行过程中数据是如何存储的,你得要知道存储空间的种类。以下是JavaScript的内存模型:
JavaScript内存模型
从图中可以看出,JavaScript的执行过程中,主要有三种类型内存空间,分别是代码空间栈空间堆空间。其中代码空间,主要是存储可执行代码的,我们这里主要讲栈空间堆空间

栈空间和堆空间

    function foo() {var a = "极客时间"var b = a;var c = { name: "极客时间" }var d = c;}foo()

JavaScript拿到一段代码的时候,需要先编译,并且创建执行上下文,然后再按照顺序执行代码,我们看下这张调用栈的状态图:
在这里插入图片描述
从上图我们可以看到 原始数据的值都是直接保存在“栈”中的,引用类型的值是存放在“堆”中的。那你可以还会好奇,为什么要分“堆”和“栈”两个存储空间呢?为什么直接把数据存放在“栈”中呢?

答案是不可以,这是因为 JavaScript 引擎需要用栈来维护程序执行期间上下文的状态,如果栈空间大了话,所有的数据都存放在栈空间里面,那么会影响到上下文切换的效率,进而又影响到整个程序的执行效率。比如文中的 foo 函数执行结束了,JavaScript 引擎需要离开当前的执行上下文,只需要将指针下移到上个执行上下文的地址就可以了,foo 函数执行上下文栈区空间全部回收。

所以,在通常情况下,栈空间都不会设置太大,主要用来存放一些原始类型的小数据。而引用类型的数据占空间都比较大,所以这类数据会被存放在堆中,堆空间很大,能存放很多大的数据。

回归文章正题,我们已经知道了JavaScript中的数据是如何存储的,不过有些数据被使用之后,可能就不再需要了,我们把这种数据叫做垃圾数据。如果这些垃圾数据一直保存在内存中,那么内存的垃圾会越来越多,所以我们需要对这些垃圾数据进行回收,以释放有限的内存空间。

不同语言的垃圾回收策略

通常情况下,垃圾数据回收分为手动回收自动回收两种策略。
比如 C/C++ 就是使用手动回收策略,何时分配,何时销毁内存都是由代码控制的;JavaScript,Java,Python等语言,产生的垃圾数据是由垃圾回收器来释放的,并不需要手动通过代码来释放。对于JavaScript而言,也正是这个“自动”释放资源的特性,让很多人觉得可以不关心内存管理,这是一个很大的误解。

所以接下来我们就来分别介绍“栈中的垃圾数据” 和 “堆中的垃圾数据”是如何回收的。

调用栈中的数据是如何回收的

具体看代码:

   function foo() {var a = 1;var b = { name: "极客邦" };function showName() {var c = "极客时间";var d = { name: "极客时间" }}showName()}foo()

其调用栈和堆空间状态图如下:
在这里插入图片描述
创建完执行上下文,接下来就是执行代码,当执行到showName函数时,与此同时,还有一个记录当前执行状态的指针(称为ESP),指向调用栈中showName函数的执行上下文,表示当前正在执行showName函数。

接着,当 showName 函数执行完成之后,函数执行流程就进入了 foo 函数,那这时就需要销毁 showName 函数的执行上下文了。ESP 这时候就帮上忙了,JavaScript 会将 ESP下移到 foo 函数的执行上下文,这个下移操作就是销毁 showName 函数执行上下文的过程。
栈中回收showName执行上下文
所以说,当一个函数执行结束后,JavaScript引擎会通过向下移动ESP来销毁函数保存在栈中的执行上下文。

堆中的数据是如何回收的

当上面那段代码foo函数执行结束之后,ESP应该是指向全局执行上下文,那这样的话showName 函数和 foo 函数的执行上下文就处于无效状态了,不过保存在堆中的两个对象依然占用着空间,如下图所示:
在这里插入图片描述
要回收堆中的垃圾数据,就需要用到JavaScript中的垃圾回收器了。所以接下来我们就通过Chrome的JavaScript引擎V8来分析下堆中的垃圾数据是如何回收的。

V8,谷歌收购并使用 C++开发并开源的 JavaScript & WebAssembly引擎,运用于 Chrome 浏览器 & Node.js,所以我们写的 JavaScript 应用,大多数都跑在 V8 上;它的作用就是,让我们所写的JavaScript代码能够让机器识别。

在V8中会把堆分为新生区老生区两个区域,新生代中存放的是生存时间短的对象,老生代中存放的生存时间久的对象。新生区通常只支持1~8M的容量,而老生区支持的容量就大很多了。对于这两块区域,V8分别使用两个不同的垃圾回收器,以便高效地实施垃圾回收。

副垃圾回收器,主要负责新生区的垃圾回收。
主垃圾回收器,主要负责老生区的垃圾回收。

副垃圾回收器

副垃圾回收器主要负责新生区的垃圾回收,通常情况下,大部分小的对象会被分到新生区,所以说这个区域虽然不大,但是垃圾回收的还是挺频繁的。

新生区中使用Scavenge算法来处理。所谓 Scavenge 算法,是把新生区空间对半划分为两个区域,一半是对象区域,一半是空闲区域,如下图所示:
在这里插入图片描述
新加入的对象都会存到对象区域,当对象区域快被写满时,就需要执行一次垃圾清理操作:

  1. 首先对对象区域中的垃圾做标记
  2. 垃圾清除阶段,副垃圾回收器会把这些存活的对象复制到空闲区域中,同时还会把这些对象有序地排列起来,所以这个过程也算是完成了内存整理操作,复制后空闲区域就没有内存碎片了。
  3. 完成复制之后,对象区域与空闲区域进行角色翻转也就是原来的对象区域变成空闲区域,原来的空闲区域变成了对象区域。

这样就完成了垃圾对象的回收操作,同时这种角色翻转的操作还能让新生区中的这两块区域无限重复使用下去。

由于新生代中采用的Scavenge算法,所以每次执行清理操作,都需要将存活的对象从对象区域复制到空闲区域,但复制操作需要时间成本,如果新生区空间设置太大,那么每次清理的时间就会很久,所以为了执行效率,一般新生区的空间会被设置得比较小。

也正是因为新生区的空间不大,所以很容易被存活的对象装满整个区域。为了解决这个问题,JavaScript 引擎采用了对象晋升策略,也就是经过 两次垃圾 回收依然还存活的对象,会被移动到老生区中。

主垃圾回收器

主垃圾回收器主要负责老生区中的垃圾回收。除了新生区中晋升的对象,一些大的对象会直
接被分配到老生区。因此老生区中的对象有两个特点,一个是对象占用空间大,另一个是对
象存活时间长。

老生区采用Mark-Sweep(标记-清除)算法进行垃圾回收,以下是它的过程:

  1. 标记过程:递归遍历元素,在遍历得过程中,能够到达的元素称为活动对象,没有到达的元素称为垃圾数据,把垃圾数据做标记;

什么算是能够到达的元素,什么算是不能到达的元素?
比如前一个代码例子,当showName函数执行退出之后,这段调用栈和堆空间如下图所示:
在这里插入图片描述
从上图你可以大致看到垃圾数据的标记过程,当 showName 函数执行结束之后,ESP 向下移动,指向了 foo 函数的执行上下文,这时候如果遍历调用栈,是不会找到引用 1003 地址的变量,也就意味着 1003 这块数据为垃圾数据,做个标记。由于 1050 这块数据被变量 b 引用了,所以这块数据为活动对象。这就是大致的标记过程。

  1. 垃圾的清除过程:把标记的垃圾数据清除
  2. 标记-整理算法,把垃圾数据清除后产生的大量不连续内存碎片进行整理,让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
    在这里插入图片描述
    现在你知道了V8是使用副垃圾回收器和主垃圾回收器处理垃圾回收的,到这也差不多文章末尾了,最后我们来总结下。

总结

在这里插入图片描述


http://chatgpt.dhexx.cn/article/b7eqIh46.shtml

相关文章

认识V8引擎

1、前言 编程语言一般分为两类,解释性语言和编译性语言。编译型语言在执行之前要先进行完全编译,而解释型语言一边编译一边执行,很明显编译型语言会比解释性语言快,而JavaScript就是一种解释型脚本语言,支持动态类型、…

V8引擎执行原理

v8是C编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。 它实现ECMAScript和WebAssembly。 v8可独立运行,也可嵌入到任何C应用程序中。 parse模块 parse模块会将JavaScript代码转换成AST(抽象语法树),因为…

Google V8引擎浅析

前端开发人员都会遇到一个流行词:V8。它的流行程度很大一部分是因为它将JavaScript的性能提升到了一个新的水平。是的,V8很快。但它是如何发挥它的魔力? 前言 源代码:https://source.chromium.org/chromium/chromium/src//master:…

js中v8引擎的详解-看的吐血

v8引擎出现的原因 这里先说一下什么是编译型语言和解释性语言: 编译型语言: 在程序执行之前必须进行专门的编译过程,有如下特点: 只须编译一次就可以把源代码编译成机器语言,后面的执行无须重新编译,直接…

Google V8 引擎

V8的前世今生 V8是JavaScript渲染引擎,第一个版本随着Chrome的发布而发布(具体时间为2008年9月2日)。在运行JavaScript之前,相比其它的JavaScript的引擎转换成字节码或解释执行,V8将其编译成原生机器码(IA-32, x86-64, ARM, or M…

编译v8引擎

本机环境是win7vs2010(本来想用2012的,但是发现默认的项目是2010的) 1、首先下载V8的源码 安装好svn,并在cmd下能使用svn help: svn下载地址(安装包):http://download.csdn.net/detail/zengraoli/5651551 …

JavaScript引擎—V8引擎

为什么需要Javascript引擎? 随着JS承担的工作越来越多,早就已超越创造出的初衷(表单验证)的范畴,因此需要快速的解析和执行JavaScript脚本 V8引擎由此而生 JavaScript引擎主要功能:结合JS语言特性 和 本质 …

LVGL V8

本文适用于LVGL V8版本 LVGL simulator vs2019 官方工程 lv_sim_visual_studio 使用注意事项: 1、将官方工程从github上下载下来,最好使用git 将整个工程clone下来,因为工程内部有依赖,如果只是将工程Download下来,无…

为什么V8引擎这么快?

转载请注明出处:http://blog.csdn.net/horkychen Google研发的V8 JavaScript引擎性能优异。我们请熟悉内部程序实现的作者依源代码来看看V8是如何加速的。 作者:Community Engine公司研发部研发工程师Hajime Morita Google的Chrome中的V8 JavaScript引擎&#xff0…

垃圾回收机制之v8引擎

v8的内存分配 (栈(执行环境)跟堆) 堆内存负责垃圾回收机制,只有新生代和老生代两部分 新生代:对等分的(严格) 老生代: 都是由新生代转变的(连续的空间&…

V8 JavaScript引擎

简介 V8 (v8.dev)是 Google 的开源高性能 JavaScript 和 WebAssembly 引擎,用 C 编写。它用于 Chrome 和 Node.js 等。它实现了 ECMAScript 和 WebAssembly,并运行在 Windows 7 或更高版本、macOS 10.12 以及使用 x64、IA-32、ARM 或 MIPS 处理器的 Lin…

V8、JSCore、Hermes、QuickJS,hybrid开发JS引擎怎么选

📌 如果你喜欢我写的文章,可以把我的公众号设为星标 🌟,这样每次有更新就可以及时推送给你啦 在一般的移动端开发场景中,每次更新应用功能都是通过 Native 语言开发并通过应用市场版本分发来实现的。 但是市场瞬息万变…

v8引擎详解

前言 JavaScript绝对是最火的编程语言之一,一直具有很大的用户群,随着在服务端的使用(NodeJs),更是爆发了极强的生命力。编程语言分为编译型语言和解释型语言两类,编译型语言在执行之前要先进行完全编译&am…

Chrome V8引擎介绍

随着Web相关技术的发展,JavaScript所要承担的工作也越来越多,早就超越了“表单验证”的范畴,这就更需要快速的解析和执行JavaScript脚本。V8引擎就是为解决这一问题而生,在node中也是采用该引擎来解析JavaScript。V8是如何使得Jav…

V8引擎原理

V8引擎原理 V8是用C编写的Googl开源高性能JavaScript和WebAssembly引擎,它也用于Chrome和Node.js等 V8的解析js的流程 js直接放到cpu中无法执行,需要通过v8转换js先被转换成ast语法树,在此期间主要是进行词法分析和语法分析ast语法树通过…

聊聊V8引擎

V8 是什么 V8 是 Google 开源的 JavaScript 引擎。可以理解为:V8 将程序员写的代码,最终解析成机器码能够让计算机识别。其中的具体操作,就是 V8 干的事。我们把 V8 看成一个黑盒, 程序语言进去,通过黑盒子的处理&…

GNSS测量与数据处理第六周作业

1.简述GPS载波相位测量的基本原理 答:若卫星S发出一载波信号,该信号向各处传播。设某一瞬间,该信号在接收机R处的相位为φR,在卫星S处的相位为φS,φR、φS为从某一起点开始计算的包括整周数在内的载波相位&#xff0c…

三角测量计算三维坐标的代码_室内定位系统的三边测量与三角测量

三边测量依赖于信号强度作为距离的类比。三角测量依赖于标签信号接收的时间差。 室内资产跟踪非常流行。但是,当谈到整个室内资产跟踪时,请务必记住,它是由一组松散编织的技术组成的,每种技术都可以使用以下两种方法之一来计算位置…

MATLAB实现三边定位

MATLAB实现 trilateration_position.m % ----------------采用三边定位法对未知节点定位-------------------------------%{clc命令是用来清除命令窗口的内容。不管开启多少个应用程序,命令窗口只有一个,所以clc无论是在脚本m文件或者函数m文件调用时,clc命令都会清除命令…

基于圆展开自适应三边测量算法的室内定位

基于圆展开自适应三边测量算法的室内定位 具有无线通信功能的移动设备的日益普及刺激了室内定位服务的增长。室内定位用于实时定位设备位置,方便访问。然而,由于大量障碍物,与室外定位相比,室内定位具有挑战性。全球定位系统非常适…