当前位置: 首页 > news >正文

V8引擎是如何提升对象属性访问速度的?

JavaScript 中的对象是由一组组属性和值的集合,从 JavaScript 语言的角度来看,JavaScript 对象像一个字典,字符串作为键名,任意对象可以作为键值,可以通过键名读写键值。

然而在 V8 实现对象存储时,并没有完全采用字典的存储方式,这主要是出于性能的考量。因为字典是非线性的数据结构,查询效率会低于线性的数据结构,V8 为了提升存储和查找效率,采用了一套复杂的存储策略。
未命名文件.png
接下来我们就来分析下 V8 采用了哪些策略提升了对象属性的访问速度。

在开始之前,我们先来了解什么是对象中的常规属性排序属性,你可以先参考下面这样一段代码:

function Fn() {this[333] = 'henshao-333'this[1] = 'henshao-1'this["B"] = 'jpd-B'this[50] = 'henshao-50'this[9] = 'henshao-9'this[8] = 'henshao-8'this[1.5] = 'jpd-1.5'this[3] = 'henshao-3'this[5] = 'henshao-5'this["A"] = 'jpd-A'this["C"] = 'jpd-C'this["8.5"] = 'jpd-8.5'
}
var test = new Fn()for(key in test){console.log(`key:${key} value:${test[key]}`)
}

下面就是执行这段代码所打印出来的结果:

key:1 value:henshao-1
key:3 value:henshao-3
key:5 value:henshao-5
key:8 value:henshao-8
key:9 value:henshao-9
key:50 value:henshao-50
key:333 value:henshao-333
key:B value:jpd-B
key:1.5 value:jpd-1.5
key:A value:jpd-A
key:C value:jpd-C
key:8.5 value:jpd-8.5

对象包含了整数、浮点数、整数字符串、字符串,但是输出结果明显没有按照我们所设置的顺序。

而且通过观察发现,数字属性是被最先打印出来的,并且按照其大小进行输出;字符串或者数字字符串和浮点类型是按照之前设置的顺序进行输出。

所以 V8 引擎应该是对不同类型的对象属性的存储进行了一定的约束。下面开始介绍具体规则。

排序属性 (elements)和常规属性 (properties)

在 V8 的对象中有两种属性,排序属性 (elements)和常规属性 (properties)。

  • 把对象中的数字属性称为排序属性,在 V8 中被称为 elements。数字属性应该按照索引值大小升序排列。
  • 字符串属性就被称为常规属性,在 V8 中被称为 properties,字符串属性根据创建时的顺序升序排列。

两个属性都存在时,排序属性 (elements)先于常规属性(properties)

在 V8 内部,为了有效地提升存储和访问这两种属性的性能,分别使用了两个线性数据结构来分别保存排序属性和常规属性,具体结构如下图所示:
未命名文件 (1).png
通过上图我们可以发现,test 对象包含了两个隐藏属性:elements 属性和 properties 属性。

如果执行索引操作,那么 V8 会先从 elements 属性中按照顺序读取所有的元素,然后再在 properties 属性中读取所有的元素,这样就完成一次索引操作。

内属性、快属性和慢属性

将不同的属性分别保存到 elements 属性和 properties 属性中,虽然简化了程序的复杂度,但是在查找元素时,却多了一步操作,比如执行 test.B 这个语句来查找 B 的属性值,那么在 V8 会先查找出 properties 属性所指向的对象 properties,然后再在 properties 对象中查找 B 属性,这种方式在查找过程中增加了一步操作,因此会影响到元素的查找效率。

基于这个原因,V8 采取了一个权衡的策略以加快查找属性的效率,这个策略是将部分常规属性直接存储到对象本身,我们把这称为对象内属性 (in-object properties)。 对象在内存中的展现形式你可以参看下图:
未命名文件 (2).png
采用对象内属性之后,常规属性就被保存到 test 对象本身了,这样当再次使用test.B来查找 B 的属性值时,V8 就可以直接从 test 对象本身去获取该值就可以了,这种方式减少查找属性值的步骤,增加了查找效率。

不过对象内属性的数量是固定的,默认是 10 个,如果添加的属性超出了对象分配的空间,则它们将被保存在常规属性存储中。虽然属性存储多了一层间接层,但可以自由地扩容。

通常,我们将保存在线性数据结构中的属性称之为**“快属性”**,因为线性数据结构中只需要通过索引即可以访问到属性,虽然访问线性结构的速度快,但是如果从线性结构中添加或者删除大量的属性时,则执行效率会非常低,这主要因为会产生大量时间和内存开销。

因此,如果一个对象的属性过多时,V8 就会采取另外一种存储策略,那就是**“慢属性”**策略,但慢属性的对象内部会有独立的非线性数据结构 (词典) 作为属性存储容器。所有的属性元信息不再是线性存储的,而是直接保存在属性字典中。
未命名文件 (3).png

相较于对象内属性,在properties中的常规属性需要额外多一次 properties 的寻址时间,之后便是与对象内属性一致的线性查找(properties 的属性是有规律的类似数组、链表存放)

【排序属性】、【对象内属性】、部分【常规属性】都属于线性数据结构,所以都叫【快属性】。
非线性数据结构是【慢属性】

实例:在 Chrome 中分析对象布局

现在我们知道了 V8 是怎么存储对象的了,接下来我们来结合 Chrome 中的内存快照,来看看对象在内存中是如何布局的?

你可以打开 Chrome 开发者工具,先选择控制台标签,然后在控制台中执行以下代码查看内存快照:

常规属性小于等于10个

function Fn(element_num, property_num) {// 添加可索引属性for (let i = 0; i < element_num; i++) {this[i] = `element${i}`}// 添加常规属性for (let i = 0; i < property_num; i++) {let ppt = `property${i}`this[ppt] = ppt}
}var test = new Fn(10,10)

上面我们创建了一个构造函数,可以利用该构造函数创建了新的对象,我给该构造函数设置了两个参数 property_num、element_num,分别代表创建常规属性的个数和排序属性的个数,我们先将这两种类型的个数都设置为 10 个,然后利用该构造函数创建了一个新的 test 对象。

创建了函数对象,接下来我们就来看看构造函数和对象在内存中的状态。你可以将 Chrome 开发者工具切换到 Memory 标签,然后点击左侧的小圆圈就可以捕获当前的内存快照,最终截图如下所示:
image.png

上图就是收集了当前内存快照的界面,要想查找我们刚才创建的对象,你可以在搜索框里面输入构造函数 Fn,Chrome 会列出所有经过构造函数 Fn 创建的对象,如下图所示:
image.png

观察上图,我们搜索出来了所有经过构造函数 Fn 创建的对象,点开 Fn 的那个下拉列表,第一个就是刚才创建的 test 对象,我们可以看到 test 对象有一个 elements 属性,这里面就包含我们创造的所有的排序属性,那么怎么没有常规属性对象呢?

这是因为只创建了 10 个常规属性,所以 V8 将这些常规属性直接做成了 test 对象的对象内属性。

所以这时候的数据内存布局是这样的:

  • 10 个常规属性作为对象内属性,存放在 test 函数内部;
  • 10 个排序属性存放在 elements 中。

常规属性大于10个小于等于20个

接下来我们可以将创建的对象属性的个数调整到 20 个,你可以在控制台执行下面这段代码:

var test2 = new Fn(10, 20)

然后我们再重新生成内存快照,再来看看生成的图片:
image.png

我们可以看到,构造函数 Foo 下面已经有了两个对象了,其中一个 test,另外一个是 test2,我们点开第第一个 Fn 对象,内容如下所示:
image.png

由于创建的常用属性超过了 10 个,所以另外 10 个常用属性就被保存到 properties 中了,注意因为 properties 中只有 10 个属性,所以依然是线性的数据结构,我们可以看其都是按照创建时的顺序来排列的。

所以这时候属性的内存布局是这样的:

  • 10 个常规属性直接存放在 test2 的对象内 ;
  • 10 个剩余的常规属性以线性数据结构的方式存放在 properties 属性里面 ;
  • 10 个数字属性存放在 elements 属性里面。

常规属性大于20个

如果常用属性太多了,比如创建了 100 个,那么我们再来看看其内存分布,你可以执行下面这段代码:

var test3 = new Fn(10, 100)

然后以同样的方式打开 test3,查看其内存布局,最终如下图所示:
image.png

结合上图,我们可以看到,这时候的 properties 属性里面的数据并不是线性存储的,而是以非线性的字典形式存储的,所以这时候属性的内存布局是这样的:

  • 10 个常规属性直接存放在 test3 的对象内 ;
  • 90 个剩余的常规属性以非线性的散列表(字典)(哈希-分离链路)形式存储在 properties 属性里面 ;
  • 10 个数字属性存放在 elements 属性里面。

附:分离链路是哈希 key +链表 value 的结构,可以存储联系复杂的数据。

为什么需要慢属性,不直接使用快属性?

假设查找 100 多个属性,要进行 100 多次运算,还不如一次哈希计算(假如 50 次简单运算)+链路检索(小于 50 次)来得更快。

总结

排序顺序数字按大小排序,字符串按先后执行顺序排序
● 在 V8 内部,为了有效地提升存储和访问这两种属性的性能,**分别使用了两个线性数据结构来分别保存排序属性和常规属性。**分解成这两种线性数据结构之后,如果执行索引操作,那么 V8 会先从 elements 属性中按 照顺序读取所有的元素,然后再在 properties 属性中读取所有的元素,这样就完成一次索引操作。
● 对象内属性,将部分常规属性 直接存储到对象本身, 对象内属性的数量是固定的,默认是 10 个(也就是说属性小于等于10个会生成内部属性),如果添加的属性超出了对象分配的空间,它们将被保存在常规属性properties存储中(大于10个在 properties 里线性存储, 数量再大的情况改为散列表存储)。
● 如果对象中的属性过多时(没有确定的数),或者存在反复添加或者删除属性的操作,那么 V8 就会将线性的存储模式降级为非线性的字典存储模式,这样虽然
降低了查找速度,但是却提升了修改对象的属性的速度。

相关文章:

V8引擎是如何提升对象属性访问速度的?

JavaScript 中的对象是由一组组属性和值的集合&#xff0c;从 JavaScript 语言的角度来看&#xff0c;JavaScript 对象像一个字典&#xff0c;字符串作为键名&#xff0c;任意对象可以作为键值&#xff0c;可以通过键名读写键值。 然而在 V8 实现对象存储时&#xff0c;并没有…...

彩色相机工作原理——bayer格式理解

早期&#xff0c;图像传感器只能记录光的强弱&#xff0c;无法记录光的颜色&#xff0c;所以只能拍摄黑白照片。 1974年,拜尔提出了bayer阵列&#xff0c;发明了bayer格式图片。不同于高成本的三个图像传感器方案&#xff0c;拜尔提出只用一个图像传感器&#xff0c;在其前面放…...

IDEA中DEBUG技巧

Debug 介绍 Debug 设置 如上图标注 1 所示&#xff0c;表示设置 Debug 连接方式&#xff0c;默认是 Socket。Shared memory 是 Windows 特有的一个属性&#xff0c;一般在 Windows 系统下建议使用此设置&#xff0c;相对于 Socket 会快点。 ## Debug 常用快捷键 Win 快捷键M…...

人工智能训练师

人工智能训练师是一个较新的职业&#xff0c;2020年2月才被正式纳入国家职业分类目录。他们主要负责在人工智能产品使用过程中进行数据库管理、算法参数设置、人机交互设计、性能测试跟踪及其他辅助作业。 这个职业的背景源于AI公司从客户&#xff08;用户&#xff09;那里获取…...

【业务功能118】微服务-springcloud-springboot-Kubernetes集群-k8s集群-KubeSphere-OpenELB部署及应用

OpenELB部署及应用 一、OpenELB介绍 网址&#xff1a; openelb.io OpenELB 是一个开源的云原生负载均衡器实现&#xff0c;可以在基于裸金属服务器、边缘以及虚拟化的 Kubernetes 环境中使用 LoadBalancer 类型的 Service 对外暴露服务。OpenELB 项目最初由 KubeSphere 社区发…...

Unity中Shader的模板测试

文章目录 前言什么是模板测试1、模板缓冲区2、模板缓冲区中存储的值3、模板测试是什么&#xff08;看完以下流程就能知道模板测试是什么&#xff09;模板测试就是在渲染&#xff0c;后渲染的物体前&#xff0c;与渲染前的模板缓冲区的值进行比较&#xff0c;选出符合条件的部分…...

Scala 高阶:Scala中的模式匹配

一、概述 Scala中的模式匹配&#xff08;case&#xff09;类似于Java中的switch...case&#xff0c;但是Scala的模式匹配功能更为强大。通过模式匹配&#xff0c;可以匹配更复杂的条件和数据结构&#xff0c;包括常量、类型、集合、元组等。而 Java 的 switch 语句只能用于匹配…...

分子生物学——分子机器

分子生物学——分子机器 文章目录 前言一、2016年度诺贝尔化学奖1.1. 介绍1.2. 什么是分子机器&#xff1f;1.3. 分子机器的意义 总结 前言 对于本次搜集分子生物学领域的一个诺贝尔奖的有关内容的作业 参考文献&#xff1a; https://www.cas.cn/zt/sszt/2016nobelprize/hxj/2…...

【简历优化】这套「实习、初级、中级」测试工程师求职简历模板,建议收藏。

历时2年&#xff0c;7000粉丝问答&#xff0c;帮助上百位“刚培训毕业”、“1~3年经验”的软件测试伙伴&#xff0c;成功入职&#xff01; 我将这些问题内容&#xff0c;会持续更新记录在 「软件测试」求职指南 专栏。 求职简历中的误区 对于简历应该具备哪些模块&#xff0c…...

vue中展示json数据的方法

推荐插件&#xff1a;bin-code-editor (gitee.io) bug-1:编辑器无法显示数据 原因&#xff1a;组件层级套用太深&#xff0c;导致无法显示数据 解决办法&#xff1a;减少在孙子及后代组件中使用插件。...

【SG滤波】三阶滤波、五阶滤波、七阶滤波(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

2013 ~【VUE+ ElementUI】——【上传、下载】进度计算

【VUE ElementUI】——【上传、下载】进度计算 上传&#xff1a;FormData方式上传&#xff0c;监听 onUploadProgress下载&#xff1a;blob文件流下载&#xff0c;监听 onDownloadProgress 上传&#xff1a;FormData方式上传&#xff0c;监听 onUploadProgress <el-upload:…...

android可见即可说实现方案

依赖于科大讯飞的asr识别能力&#xff0c;使用Android无障碍服务获取页面文本作为热词&#xff0c;注册到讯飞api&#xff0c;注册过后语音识别到热词的asr返回,利用WindowManager和无障碍的点击实现可见即可说功能 ## &#x20;无障碍服务获取需要注册的热词package com..mo…...

Pikachu Burte Force(暴力破解)

一、Burte Force&#xff08;暴力破解&#xff09;概述 ​ “暴力破解”是一攻击具手段&#xff0c;在web攻击中&#xff0c;一般会使用这种手段对应用系统的认证信息进行获取。 其过程就是使用大量的认证信息在认证接口进行尝试登录&#xff0c;直到得到正确的结果。 为了提高…...

SpringMVC之JSON返回及异常处理

目录 JSON处理 导入依赖 配置Spring-mvc.xml ResponseBody注解使用 测试 目录 JSON处理 导入依赖 配置Spring-mvc.xml ResponseBody注解使用 测试 Jackson 定义 用法 常用注解 统一异常处理 为什么要全局异常处理&#xff1f; 异常处理思路 SpringMVC异常分类 综…...

SkyWalking快速上手(六)——告警

文章目录 前言一、什么是SkyWalking的告警功能二、为什么要使用SkyWalking的告警功能1. 及时发现异常情况2. 提高故障处理效率3. 避免数据丢失和损坏4. 提升系统性能和稳定性 三、如何使用SkyWalking的告警功能1. 告警规则2. 告警通知3. 告警持续时间 四、注意事项1、合理设置告…...

docker run:--privileged=true选项解析(特权模式:赋予容器几乎与主机相同的权限)

文章目录 Docker的--privilegedtrue选项1. Docker 容器的安全性1.1 Linux Namespace 和 Capabilities1.2 限制和权限 2. Docker的--privilegedtrue选项2.1 --privilegedtrue的作用2.2 --privilegedtrue的风险 3. 结论 Docker的–privilegedtrue选项 Docker在创建和运行容器时&…...

计算机专业毕业设计项目推荐06-工作室管理系统(Java+Vue+Mysql)

工作室管理系统&#xff08;JavaSpringVueMysql&#xff09; **介绍****系统总体开发情况-功能模块****各部分模块实现****最后想说的****联系方式** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以也比较…...

Python 文件的读写操作

文章目录 1. 文件对象1.1 文件打开方式1.1.1 打开文件1.1.2 关闭文件1.1.3 访问模式 1.2文件读取1.2.1 read()1.2.2 readline()1.2.3 readlines() 1.3 文件迭代1.4 文件输入1.4.1 write()1.4.2 writelines() 1. 文件对象 文件读写操作&#xff1a; 把大象放冰箱里&#xff0c…...

多线程回顾、集合Collection、Set、List等基本知识

多线程回顾 问: 多线程的两种创建方式? 继承Thread类实现Runnable接口线程池Callable 问:多线程通常会遇到线程安全问题? 什么情况下会遇到线程安全问题? 答:一个数据被多个线程访问(有读有写) 解决这个问题的方式? SE:同步锁 synchronized A : 同步代码块 B : 同步方法…...

分享5款用起来很好用的软件,总有一款适合你

很多软件用起来很好用&#xff0c;但是由于这样那样的原因&#xff0c;一直没什么知名度&#xff0c;但是不代表它们不好用&#xff0c;我的任务就是把这些宝藏分享给大家。 1.图像处理——Photoscissors Photoscissors是一款在线图像背景移除工具&#xff0c;可以让你轻松地从…...

大数据学习1.5-单机Hadoop

1.修改主机信息 vi /etc/hosts 2.修改信息如下(这里第三位一定是自己的IP 每个人都不一样) 192.168.216.140 hadoop01 192.168.216.141 hadoop02 192.168.216.142 hadoop033.修改Hadoop配置信息-1进入配置信息文件 cd /usr/local/hadoop/hadoop-2.7.1/etc/hadoop/ 4.修改Had…...

Cesium对实体元素鼠标点击popup div信息框

一、简介 设置div信息框模板,给实体元素绑定事件,同步空间位置,然后在回调函数弹出信息框。 二、示例源码 <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" …...

有多条业务线,mysql建多库多表比较好还是一个库多个表比较好呢?

这个问题的答案取决于您的具体需求。以下是一些需要考虑的因素&#xff1a; 数据独立性&#xff1a;如果您的业务线之间的数据是独立的&#xff0c;并且不太可能需要进行跨业务线的查询&#xff0c;那么将它们分成多个数据库可能是有意义的。这样可以使每个业务线的数据更加独…...

C++---异常处理

异常处理 异常处理try语句块和throw表达式异常的抛出和捕获异常的抛出和匹配原则 异常安全异常规范标准异常 异常处理 异常是指存在于运行时的反常行为&#xff0c;这些行为超出了函数正常功能的范围。当程序的某部分检测到一个他无法处理的问题时&#xff0c;需要用到异常处理…...

接口自动化测试(Python+Requests+Unittest)

(1)接口自动化测试的意义、前后端分离思想 接口自动化测试的优缺点&#xff1a; 优点&#xff1a; 测试复用性。 维护成本相对UI自动化低一些。 为什么UI自动化维护成本更高&#xff1f; 因为前端页面变化太快&#xff0c;而且UI自动化比较耗时&#xff08;比如等待页面元素的…...

驱动开发,IO多路复用(select,poll,epoll三种实现方式的比较)

1.IO多路复用介绍 在使用单进程或单线程情况下&#xff0c;同时处理多个输入输出请求&#xff0c;需要用到IO多路复用&#xff1b;IO多路复用有select/poll/epoll三种实现方式&#xff1b;由于不需要创建新的进程和线程&#xff0c;减少了系统资源的开销&#xff0c;减少了上下…...

大数据-玩转数据-oracel字符串分割转化为多列

一、建表 create table split_string_test(id integer primary key,test_string varchar2(500) );二、插入测试数据 insert into split_string_test values(1, 10,11,12,13,14,22); insert into split_string_test values(2, 22,23,24); insert into split_string_test valu…...

GCP设置Proxy来连接Cloud SQL

在之前的文章用Google CDC来同步Cloud SQL的数据到Bigquery_gzroy的博客-CSDN博客中&#xff0c;我通过在一个VM上设置反向代理的方式&#xff0c;使得Datastream可以通过私用连接连到Cloud SQL数据库进行数据复制。但是这种方式不太方便&#xff0c;主要是VM的状态我们不太方便…...

Python:为何成为当下最热门的编程语言?

文章目录 &#x1f34b;引言&#x1f34b;1. 简单易学&#x1f34b;2. 多领域应用&#x1f34b;3. 强大的社区支持&#x1f34b;4. 丰富的库和框架&#x1f34b;5. 跨平台兼容&#x1f34b;6. 开源和免费&#x1f34b;7. 数据科学和人工智能的崛起&#x1f34b;8. 自动化和脚本…...

大型电子商务网站建设公司/电商运营基础知识

环境&#xff1a;Centos 5.5 将 二&#xff1a;192.168.226.250 的配置清除重新配置 两台虚拟机 一&#xff1a;192.168.226.136 三&#xff1a;192.158.226.250 一&#xff1a;修改 三&#xff1a;192.158.226.250 的named.conf 如下 二&#xff1a;重启&#xff0c;测…...

企业网站首页布局设计/seo网站诊断流程

虚拟内存盘是通过软件将一部分内存&#xff08;RAM&#xff09;模拟为硬盘来使用的一种技术。相对于直接的硬盘文件访问来说&#xff0c;这种技术可以极大的提高在其上进行的文件访问的速度。但是RAM的易失性也意味着当关闭电源后这部分数据将会丢失。但是在一般情况下&#xf…...

加强网站信息怎么做/seo排名优化软件有

我们身边的电磁波越来越多了。随着无线路由器的普及&#xff0c;无线网络信号似乎每天24小时辐射着我们。那么我们不禁要问问&#xff0c;WIFI对人究竟有没有危害? 这个问题总是不断地被提及&#xff0c;简而言之&#xff0c;答案是不会。事实上&#xff0c;将您的问题换一个方…...

济南疫情最新通报/西安企业seo外包服务公司

一、继承 1.什么继承 继承是一种创建新类的方式&#xff0c;新建的类可以继承一个或多个父类&#xff08;python支持多继承&#xff09;&#xff0c;父类又可称为基类或超类&#xff0c;新建的类称为派生类或子类。 2.为什么要有继承 子类会“”遗传”父类的属性&#xff0c;从…...

福州成人报考网站/新闻热搜榜 今日热点

1.在firefox下&#xff0c;每页均会打印重复thead(表头)&#xff0c;tfoot(表尾)的内容&#xff1b;IE8下无效(其它IE版本未测试)2.分页的处理media print {.page-break { page-break-after: always; }}在需要分页的tr上&#xff0c;加上该样式即可3.隐藏某些不需要打印的区域m…...

佛山网站建设运营/成都网站优化

Redis作为缓存中间件&#xff0c;被广泛应用在各类系统&#xff0c;用来提升系统性能和吞吐&#xff0c;下面总结几点开发人员在使用Redis时需要考虑的几个关键点&#xff1a; 一. key的设计 key命名规范&#xff1a;为了避免不必要的麻烦&#xff0c;我们要给系统定义一套key…...