adodo0829 / blog

搭建知识体系
29 stars 4 forks source link

v8 下的数组实现 #99

Open adodo0829 opened 2 years ago

adodo0829 commented 2 years ago

v8 下的数组实现

V8 中对数组做了一层封装,使其有两种实现方式:

js 中的数组

c++中的数组是通过在内存中划分一串连续的、固定长度的空间,来实现存放一组有限个相同数据类型的数据结构。即内存连续固定长度相同数据类型

/**
js数组中不止可以存放上面的三种数据类型,它可以存放数组、对象、函数、Number、Undefined、Null、String、Boolean 等等。
js数组可以动态的改变容量,根据元素的数量来扩容、收缩。
js数组可以表现的像栈一样,为数组提供了push()和pop()方法。也可以表现的像队列一样,使用shift()和 push()方法,可以像使用队列一样使用数组。
*/

const arr = [1, 2, 3, "a", "b", {}, false];
arr[arr.length] = "hello";

快速的后备存储结构是 FixedArray ,并且数组长度 <= elements.length(); 快数组是一种线性的存储方式。新创建的空数组,默认的存储方式是快数组,快数组长度是可变的,可以根据元素的增加和删除来动态调整存储空间大小,内部是通过扩容和收缩机制实现

缓慢的后备存储结构是一个以数字为键的 HashTable; 散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。 这个映射函数称做散列函数,存放记录的数组称做散列表。

常见的 hashTable

慢数组是一种字典的内存形式。不用开辟大块连续的存储空间,节省了内存,但是由于需要维护这样一个 HashTable,其效率会比快数组低

快慢数组的区别

存储方式方面:快数组内存中是连续的,慢数组在内存中是零散分配的。

内存使用方面:由于快数组内存是连续的,可能需要开辟一大块供其使用,其中还可能有很多空洞,是比较费内存的。慢数组不会有空洞的情况,且都是零散的内存,比较节省内存空间。

遍历效率方面:快数组由于是空间连续的,遍历速度很快,而慢数组每次都要寻找 key 的位置,遍历效率会差一些。

快慢数组转换

1.新容量 >= 3 扩容后的容量 2 ,会转变为慢数组。 2.当加入的 index- 当前capacity >= kMaxGap(1024) 时(也就是至少有了 1024 个undefined元素),会转变为慢数组。

哈希表实现的数组,在每次空间增长时, V8 的启发式算法会检查其空间占用量, 若其空洞元素(undefined & null)减少到一定程度,则会将其转化为快数组模式。

ArrayBuffer

ArrayBuffer: ES6中 按照需要分配连续内存的数组

ArrayBuffer会从内存中申请设定的二进制大小的空间,但是并不能直接操作它,需要通过ArrayBuffer构建一个视图,通过视图来操作这个内存

// 申请了 1kb 的内存区域
const buffer = new ArrayBuffer(1024)

// buffer不能修改, 需要将它赋给一个视图来操作内存
const arr = new Int32Array(buff)
// 有符号的32位的整数数组,每个数占 4 字节,长度也就是 1024 / 4 = 256 个