《突破V8性能极限 —— Nodejs应用优化观后总结》

《突破V8性能极限 —— Nodejs应用优化观后总结》

看完v8 tech leader在google IO上的演讲,做了点总结,与大家分享

视频 http://www.tudou.com/programs/view/bqxvrifP4mk/ Slide http://v8-io12.appspot.com/

Breaking the JavaScript Speed Limit with V8 Daniel Clifford Manager and Tech Lead V8 Team, Google Chrome

Hidden class 隐藏类型

每次添加新属性,v8会创造一种新的隐藏类型,这是昂贵的。

优化策略:

  1. Initialize all object members in constructor functions 在构造函数中初始化所有属性

  2. Alwayse initialize members in same order 始终按照同样顺序初始化属性

数字 Numbers

V8 用32位的空间存储变量指针,为了提高int处理效率,直接用一个标志位来表示它是int还是指针,因此,还剩下31位的空间用于存储指针或int值。当标志位为1,是对象指针,当标志位为0,是31位有符号整数,区间是 [-1073741825, 1073741824],(如本人理解有误,请各位指正)

优化策略:

  1. Prefer numeric values that can be represented as 31-bit signed integers 数字的值尽可能使用31位有符号整数。

Arrays 数组

V8数组有两种模式,一种是紧凑的快速模式,另一种是松散的字典模式。 Fast Elements: linear storage for compact key sets Dictionary Elements: hash table storage otherwise

优化策略:

  1. Use contiguous keys starting at 0 for Arrays 从0开始连续的初始化数组,否则将会转换位字典模式。

  2. Don’t pre-allocate large Arrays (e.g. > 64K elements) to their maximum size, instead grow as you go 不要预分配一个超大数组(比如64K元素),如果你只用了开始的一部分,这将转换为字典模式。

  3. Don’t delete elements in arrays, especially numeric arrays 不要删除数组中的元素,尤其是数字数组。同样会转换为字典模式。

  4. Don’t load uninitialized or deleted elements 不要访问未初始化或已删除的数组元素

Double Array Unboxing

Double数组Unboxing

Double数组是一种特殊的数组,double数组是展开的,每个元素都是直接存储double值,而非指向double值的指针。下面3句不知道如何翻译,大家自己理解吧。

Array’s hidden class tracks element types Arrays containing only doubles are unboxed Unboxing causes hidden class change

Careless manipulation of Arrays can cause extra work due to boxing and unboxing 不小心的数组操作会引起不必要的封装和展开

如下面的代码将因double数组产生2次额外的重新分配

var a = new Array();
a[0] = 77;   // 分配数组
a[1] = 88;
a[2] = 0.5;   // 重新分配,转换为展开的double数组 
a[3] = true; // 重新分配, 转换为封装的指针数组

对此的解决办法是这样:

var a = [77, 88, 0.5, true];

优化策略:

  1. Initialize using array literals for small fixed-sized arrays 尽可能对小的定长数组使用“字面数组”(array literal)初始化。

  2. Preallocate small arrays to correct size before using them 使用前为数组预分配正确的尺寸,前提是小于64k的数组。 这里有一句没听懂“but only if … ” 求听清楚的告知。

  3. Don’t store non-numeric values (objects) in numeric arrays 不要在数字数组中存入非数字值。

——待续


16 回复

《突破V8性能极限 —— Nodejs应用优化观后总结》

看完v8技术负责人在Google I/O上的演讲,做了点总结,与大家分享。

视频链接:

http://www.tudou.com/programs/view/bqxvrifP4mk/

幻灯片链接:

http://v8-io12.appspot.com/


Hidden Class 隐藏类型

每次向对象添加新属性时,V8会创建一种新的隐藏类型,这是一个开销较大的操作。

优化策略:

  1. 在构造函数中初始化所有属性

    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
  2. 始终按照相同顺序初始化属性

    function Person(name, age) {
      this.age = age;
      this.name = name;  // 不推荐这种顺序
    }
    

数字 Numbers

V8使用32位空间存储变量指针,为了提高整数处理效率,直接使用一个标志位来表示它是整数还是指针。因此,剩下的31位可以用来存储整数或指针。当标志位为1时,表示对象指针;当标志位为0时,表示31位有符号整数(范围为 ([-1073741825, 1073741824]))。

优化策略:

  1. 尽可能使用31位有符号整数
    var num = 1073741824;  // 有效的31位整数
    

数组 Arrays

V8数组有两种模式:紧凑的快速模式和松散的字典模式。紧凑模式适用于连续的索引,而字典模式适用于稀疏或不连续的索引。

优化策略:

  1. 从0开始连续初始化数组

    var arr = [0, 1, 2, 3];  // 连续的索引
    
  2. 避免预分配大数组

    var arr = [];
    for (let i = 0; i < 1000000; i++) {
      arr[i] = i;  // 动态增长,而不是一次性分配
    }
    
  3. 避免删除数组元素

    var arr = [0, 1, 2, 3];
    arr.splice(2, 1);  // 删除元素会导致转换为字典模式
    
  4. 避免加载未初始化或已删除的元素

    var arr = [0, 1, 2, 3];
    console.log(arr[4]);  // 未初始化的元素
    

Double Array Unboxing

双精度数组(Double数组)是一种特殊的数组,其中每个元素直接存储双精度浮点值,而不是指针。不恰当的操作可能导致额外的重新分配和性能损失。

优化策略:

  1. 使用字面量初始化小固定大小的数组

    var arr = [77, 88, 0.5, true];
    
  2. 预分配小数组到正确大小

    var arr = new Array(10);
    arr.fill(0);  // 预分配数组
    
  3. 不要在数字数组中存储非数字值

    var arr = [1, 2, 3, "string"];  // 避免这种情况
    

这些优化策略可以帮助你在使用Node.js时更好地利用V8引擎的性能优势。希望这些总结对你有所帮助!


这是跟具体JS引擎实现细节相关的,什么时候V8优化方式一变,编程实践就不同了……

这篇之所以有价值,因为他是v8 tech leader 所做的分享,可见它是有一定时效性的, 至少是一个不错的编码习惯.

以前发的 delete的问题就是破坏了 隐藏类型

pop 应该不算,线性转字典,主要是因为数组碎片化了.

可以实测一下试试

昨天没看完,今天继续看,一边听译吧。

可以针对每个优化点,做benchmark测试验证一下。

不错,为了系统性能,我们需要了解如何编码才能跑的更好。

既然 javascript 的语法超级简单,没有其他语言那么复杂的数据类型和数据结构,那么它一定是在内部隐含了更细更复杂的设计,理解了这个,就能写出性能更好的代码。

好东西要围观

哪都看到你的身影,如此伟岸,,

V8代码看得懂么:(

受益匪浅(fir.im)

12年的被挖坟挖出来了~

《突破V8性能极限 —— Nodejs应用优化观后总结》

看完V8技术负责人在Google I/O上的演讲,我做了些总结,希望能与大家分享:

Hidden Class 隐藏类型

每次添加新属性时,V8会创建一个新的隐藏类,这是比较昂贵的操作。

优化策略:

  1. 在构造函数中初始化所有属性。
  2. 始终按照同样顺序初始化属性。

示例代码:

function MyClass() {
    this.a = 0;
    this.b = 0;
}

数字 Numbers

V8使用32位空间存储变量指针,其中最高位作为标志位,表示该值是整数还是指针。

优化策略:

  1. 尽可能使用31位有符号整数。

示例代码:

let num = 1073741824; // 这个值可以被表示为31位有符号整数

数组 Arrays

V8支持两种数组模式:紧凑模式和字典模式。紧凑模式更高效。

优化策略:

  1. 从0开始连续初始化数组。
  2. 不要预分配超大数组(例如 > 64K元素)。
  3. 不要在数组中删除元素。
  4. 不要访问未初始化或已删除的数组元素。

示例代码:

let arr = new Array(10); // 连续初始化数组
arr[0] = 0;
arr[1] = 1;

Double Array Unboxing

双精度浮点数组(Double数组)在存储时可能会进行展开操作(unboxing),这会增加开销。

优化策略:

  1. 使用数组字面量初始化小的固定大小数组。
  2. 预分配小数组到正确大小。
  3. 不要在数字数组中存储非数字值。

示例代码:

let arr = [77, 88, 0.5, true]; // 使用数组字面量初始化

以上是对V8优化的一些总结和建议,希望对大家有所帮助。

回到顶部