V8中的对象

138 阅读3分钟

V8是一个用C++编写的JavaScript引擎,是Google Chrome浏览器的核心组件之一。V8的对象属性存储结构由两个部分组成:对象头和属性数组。

对象头是一个包含类型信息和标记位的固定大小的结构体,它记录了对象的类型和一些元信息,比如对象是否被标记为垃圾等。对象头的大小是固定的,通常为16字节。

属性数组是一个存储对象属性的数组,其中每个元素都是一个属性单元(property cell)。属性单元包含两个指针,一个指向属性的名称,另一个指向属性的值。如果属性的值是一个对象,那么该指针将指向该对象的属性数组的第一个属性单元。

在V8中,对象的属性可以分为两类:命名属性和索引属性。命名属性是指属性名为字符串的属性,它们的属性单元存储在对象属性数组的前面,通过字符串的哈希值进行快速查找。索引属性是指属性名为整数的属性,它们的属性单元存储在对象属性数组的后面,通过索引进行访问。 V8 中的命名属性存储方式主要有三种:

  1. 快属性(Fast Properties)

快属性存储在对象的连续内存区域中。在创建对象时,V8 会检查对象的初始属性,如果属性的数量和类型符合条件,就将这些属性存储在对象的连续内存区域中。这样可以快速地访问对象的属性,因为可以直接通过偏移量访问属性值,无需进行哈希表查找。

  1. 慢属性(Slow Properties)

如果对象的属性数量超过了快属性的限制,或者对象的属性类型发生了变化,V8 就会使用慢属性存储方式。慢属性存储在对象的哈希表中,通过哈希表查找可以访问对象的属性值。由于哈希表的查找复杂度是 O(1),因此慢属性的访问速度也是非常快的。

  1. 对象内属性(Dictionary Properties)

对象内属性是一种特殊的慢属性,它将对象的属性存储在对象本身的内存中。与哈希表不同,对象内属性使用的是有序的属性名列表,通过查找属性名的位置来访问属性值。由于对象内属性存储在对象本身的内存中,因此可以避免频繁地进行内存分配和释放,从而提高了内存分配的效率。但是,由于对象内属性使用的是有序的属性名列表,因此属性的访问速度比哈希表慢一些。

需要注意的是,V8 会根据对象的属性变化动态地调整属性的存储方式。如果对象的属性数量和类型符合快属性的条件,V8 就会将属性从哈希表中移动到连续的内存区域中;如果对象的属性数量超过了快属性的限制,V8 就会将属性从连续的内存区域中移动到哈希表中。这种动态的属性存储方式可以在不同情况下优化对象的访问速度和内存占用。

V8还支持一种特殊的属性类型,即“隐藏属性”(hidden property)。隐藏属性是不会被枚举和序列化的属性,它们通常用于内部实现细节。隐藏属性的属性单元存储在对象属性数组的最后面。

参考资料

chatgpt