【V8】【1. 内存布局、隐藏类Hidden Class】

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

在 ECMAScript 规范中定义了数字属性应该按照索引值大小升序排列,字符串属性根据创建时的顺序升序排列。

function Foo() {this[100] = 'test-100'this[1] = 'test-1'this["B"] = 'bar-B'this[50] = 'test-50'this[9] =  'test-9'this[8] = 'test-8'this[3] = 'test-3'this[5] = 'test-5'this["A"] = 'bar-A'this["C"] = 'bar-C'
}
var bar = new Foo()for(key in bar){console.log(`index:${key}  value:${bar[key]}`)
}index:1  value:test-1
index:3  value:test-3
index:5  value:test-5
index:8  value:test-8
index:9  value:test-9
index:50  value:test-50
index:100  value:test-100
index:B  value:bar-B
index:A  value:bar-A
index:C  value:bar-C

数字属性称为排序属性,在 V8 中被称为 elements,字符串属性就被称为常规属性,在 V8 中被称为 properties。

在 V8 内部,为了有效地提升存储和访问这两种属性的性能,分别使用了两个线性数据结构来分别保存排序属性和常规属性,具体结构如下图所示:
在这里插入图片描述
如果执行索引操作,那么 V8 会先从 elements 属性中按照顺序读取所有的元素,然后再在 properties 属性中读取所有的元素,这样就完成一次索引操作。

快属性和慢属性

v8 中将部分常规属性直接存储到对象本身,我们把这称为对象内属性
在这里插入图片描述
对象内属性的数量是固定的,默认是 10 个,如果添加的属性超出了对象分配的空间,则它们将被保存在常规属性存储中。虽然属性存储多了一层间接层,但可以自由地扩容。

通常,我们将保存在线性数据结构中的属性称之为“快属性”。

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

function Foo(property_num,element_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 bar = new Foo(20,10)

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

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

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

我们不建议使用 delete 来删除属性,因为删除后需要移动元素,开销较大,而且可能需要将慢属性重排到快属性。
如果删除属性在properties对象中,查找开销较大。

隐藏类 HiddenClass

V8 为了提升 JavaScript 的执行速度,借鉴了很多静态语言的特性,比如实现了 JIT 机制,为了提升对象的属性访问速度而引入了隐藏类,为了加速运算而引入了内联缓存。

我们知道,JavaScript 在运行时,对象的属性是可以被修改的,所以当 V8 使用了一个对象时,比如使用了 start.x 的时候,它并不知道该对象中是否有 x,也不知道 x 相对于对象的偏移量是多少,也可以说 V8 并不知道该对象的具体的形状。

静态语言的查询效率这么高,那么是否能将这种静态的特性引入到 V8 中呢?

答案是可行的。

目前所采用的一个思路就是将 JavaScript 中的对象静态化,也就是 V8 在运行 JavaScript 的过程中,会假设 JavaScript 中的对象是静态的,具体地讲,V8 对每个对象做如下两点假设:

  • 对象创建好了之后就不会添加新的属性;
  • 对象创建好了之后也不会删除属性。

V8 会为每个对象创建一个隐藏类,对象的隐藏类中记录了该对象一些基础的布局信息,包括以下两点:

  • 对象中所包含的所有的属性;
  • 每个属性相对于对象的偏移量。
let point = {x:100,y:200}

当 V8 执行到这段代码时,会先为 point 对象创建一个隐藏类,在 V8 中,把隐藏类又称为 map,每个对象都有一个 map 属性,其值指向内存中的隐藏类。

隐藏类描述了对象的属性布局,它主要包括了属性名称和每个属性所对应的偏移量,比如 point 对象的隐藏类就包括了 x 和 y 属性,x 的偏移量是 4,y 的偏移量是 8。

在这里插入图片描述

多个对象共用一个隐藏类

每次给对象添加了一个新属性之后,该对象的隐藏类的地址都会改变,这也就意味着隐藏类也随着改变了。

let point = {};
%DebugPrint(point);
point.x = 100;
%DebugPrint(point);
point.y = 200;
%DebugPrint(point);DebugPrint: 0x986080c5b35: [JS_OBJECT_TYPE]- map: 0x0986082802d9 <Map(HOLEY_ELEMENTS)> [FastProperties]- ...DebugPrint: 0x986080c5b35: [JS_OBJECT_TYPE]- map: 0x098608284ce9 <Map(HOLEY_ELEMENTS)> [FastProperties]- ...- properties: 0x0986080406e9 <FixedArray[0]> {#x: 100 (const data field 0)}DebugPrint: 0x986080c5b35: [JS_OBJECT_TYPE]- map: 0x098608284d11 <Map(HOLEY_ELEMENTS)> [FastProperties]- p- ...- properties: 0x0986080406e9 <FixedArray[0]> {#x: 100 (const data field 0)#y: 200 (const data field 1) 

最佳实践

一,使用字面量初始化对象时,要保证属性的顺序是一致的。 比如先通过字面量 x、y 的顺序创建了一个 point 对象,然后通过字面量 y、x 的顺序创建一个对象 point2,代码如下所示:

let point = {x:100,y:200};
let point2 = {y:100,x:200};

虽然创建时的对象属性一样,但是它们初始化的顺序不一样,这也会导致形状不同,所以它们会有不同的隐藏类,所以我们要尽量避免这种情况。

二,尽量使用字面量一次性初始化完整对象属性。 因为每次为对象添加一个属性时,V8 都会为该对象重新设置隐藏类。

三,尽量避免使用 delete 方法。 delete 方法会破坏对象的形状,同样会导致 V8 为该对象重新生成新的隐藏类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/26242.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FasterViT实战:使用FasterViT实现图像分类任务(一)

文章目录 摘要安装包安装timm安装 grad-cam 数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集 摘要 论文翻译&#xff1a;https://blog.csdn.net/m0_47867638/article/details/131542132 官方源码&#xff1a;https://github.com/NVlabs/FasterViT 这是一篇来自英伟…

初学者怎么学习c++(合集)

学习c方法1 找一本好的书本教材&#xff0c;辅助看教学视频。好的教材&#xff0c;可以让你更快更好的进入C/C的世界。在校学生的话&#xff0c;你们的教材通常都是不错的。如果是自学&#xff0c;推荐使用谭浩强出的C/C经典入门教材。看视频是学习比较直观的方式。建议先看课本…

Smartbi 身份认证绕过漏洞

0x00 简介 Smartbi是广州思迈特软件有限公司旗下的商业智能BI和数据分析产品&#xff0c;致力于为企业客户提供一站式商业智能解决方案。 0x01 漏洞概述 Smartbi在安装时会内置三个用户&#xff08;public、service、system&#xff09;&#xff0c;在使用特定接口时&#x…

高压放大器需要注意哪些指标

高压放大器是一种专门用于输出高电压信号的电子设备&#xff0c;主要应用于精密测量、医疗设备、电力电子等领域中。在选择高压放大器时&#xff0c;需要注意其性能指标&#xff0c;以确保设备的稳定性和可靠性。 以下是高压放大器需要注意的性能指标&#xff1a; 输出电压范围…

利用ArcGIS Pro制作三维效果图

1、新建工程 打开Arcgispro,新建工程,这里我们要用到的模板为全局场景。 2、添加数据 这里添加的数据需要有一个字段内容是数值的,这个字段也是接下来要进行拉伸的字段。 3、高度拉伸 数据添加进来后,如下图所示,这时图层处于2D图层里。 这时我们点中该图层,回到菜单栏…

Spring Cloud Gateway下的GC停顿排查之旅

01 背景 在微服务架构体系流行的当下&#xff0c;Spring Cloud全家桶已经是大多数团队的首选&#xff0c;我们也不例外&#xff0c;并且选择了Spring Cloud Gateway作为了业务网关&#xff0c;进行了一些通用能力的开发&#xff0c;如鉴权、路由等等。作为一个成熟的框架&#…

如何学习Java集合框架? - 易智编译EaseEditing

要学习Java集合框架相关的技术和知识&#xff0c;可以按照以下步骤进行&#xff1a; 掌握Java基础知识&#xff1a; 在学习集合框架之前&#xff0c;确保你已经具备良好的Java编程基础&#xff0c;包括语法、面向对象编程&#xff08;OOP&#xff09;原理和常用的核心类库等。…

win10电脑出现网络问题时,如何解决?

我们的Windows可能会出现各种网络连接问题&#xff1a; 尝试连接Wi-Fi网络时出现错误&#xff1a;Windows无法连接到此网络&#xff1b;可以通过Wifi访问互联网&#xff0c;但通过电缆访问以太网却无法正常工作&#xff1b;尝试通过电缆连接互联网时出现错误&#xff1a; Wind…

ios 启动页storyboard 使用记录

本文简单记录ios启动页storyboard 如何使用和注意事项。 xcode窗口简介 以xcode14为例&#xff0c;新建项目如下图&#xff0c;左边文件栏中的LaunchScreen.storyboard 为默认启动页布局。窗口中间部分是storyboard中的组件列表&#xff0c;右侧为预览&#xff0c;可以看到渲…

goland设置内置命令行为当前项目环境

goland设置内置的命令行为当前项目环境 修改 GoLand 中的 SSH 终端配置即可

Python正则表达式校验某个字符串是否是合格的email

Python正则表达式校验某个字符串是否是合格的email 可以借助正则表达式校验某个字符串是否是合规的电子邮箱。对于邮箱的正则表达式有严格的模式&#xff0c;如&#xff1a;^[a-zA-Z0-9_&*-](?:\\.[a-zA-Z0-9_&*-])*(?:[a-zA-Z0-9-]\\.)[a-zA-Z]{2,7}$ 对应的Python…

ESP32设备驱动-直流电机与L298N电机驱动器

直流电机与L298N电机驱动器 文章目录 直流电机与L298N电机驱动器1、L298N介绍2、硬件准备3、软件准备4、驱动实现在本文中,我们将介绍如何使用ESP32通过L298N电机驱动器驱动直流电机。 1、L298N介绍 L298N 电机驱动器模块非常易于与微控制器一起使用,而且相对便宜。 它被广泛…