Nodejs V8:抖动优化(Jank Busters)— 第一部分

发布于 1周前 作者 sinazl 来自 nodejs/Nestjs

Nodejs V8:抖动优化(Jank Busters)— 第一部分

作者:Jochen Eisinger, Michael Lippautz, Hannes Payer 译者:隔壁老王

当 Chrome 无法在 16.66ms 内渲染完一帧(破坏了每一秒渲染 60 帧)时,就会发生页面抖动( Jank ),换句话说就是肉眼可见的断断续续。截止现在(译者注:2015 年 12 月 30 号) V8 垃圾回收的大部分工作是在渲染线程(主线程)执行的,请参看图一,通常有很多对象需要维护的时候就会发生页面抖动。消除页面抖动一直是 V8 团队的重中之重([1],[2],[3])。在本文中我们会讨论 M41 到 M46 之间所做的一些优化。这些优化显著的减少了垃圾回收导致的主线程挂起,从而带来了更好的用户体验。

垃圾回收工作在主线程执行

图一:垃圾回收工作在主线程执行

垃圾收集过程中页面抖动的主要原因是处理各种簿记( bookkeeping )数据结构。许多这样的数据结构启用了和垃圾回收无关的优化。两个例子分别是所有 ArrayBuffer 的列表和每个 ArrayBuffer 的视图列表。这些列表高效的实现了 DetachArrayBuffer 这一操作,而不会对 ArrayBuffer 的视图层造成任何的性能损失。但是在有些情况下页面会创建数百万个 ArrayBuffer, 比如基于 WebGL 的游戏,在垃圾回收期间更新这些 ArrayBuffer 的列表会导致严重的抖动。在 M46 中,我们删除这些列表,并通过插入检查来检测分离缓冲区( detached buffers ),在垃圾回收的时候,这种方式分摊了处理大量簿记( bookkeeping )数据结构列表的成本,在程序执行过程中分散处理可以减少抖动。虽然理论上来说每次访问检查会降低大量使用 ArrayBuffer 的程序的吞吐量,事实上 V8 的优化编译器通常可以删除多余的检查,并将剩余的检查从循环中提升出来,可以更加平滑的执行 profile, 只有一点或者没有整体上的性能损失。

未完~ 关注公众号查看完整内容

公号


7 回复

硬核
请问大佬除了看源码,还有什么入门学习 V8 的方法么?


现在都 9102 年了,2015 年的技术会不会有点太老了…

我不是啥大佬蛤。这篇文章是我们 FENews 组织里的伙伴翻译的,我们公众号翻译的 V8 文章大多都来自 V8 的官博,如果英文好的话 可以直接看 V8 官博 https://v8.dev/ ) ,也可以关注下我们公众号的文章。

温故而知新蛤,我们也是在学习的过程中,这些 V8 的那些文章看完还是有收益的不是吗

这篇文章也是我们的伙伴在翻译 Orinoco: V8 的垃圾回收器( https://fenews.now.sh/posts/the-Orinoco-garbage-collector/) 这篇文章时参考的文章

更正 《 Orinoco: V8 的垃圾回收器》访问链接为 https://fenews.org/posts/the-Orinoco-garbage-collector/

针对“Node.js V8:抖动优化(Jank Busters)— 第一部分”的帖子,以下是我的专业回复:

Node.js的性能很大程度上依赖于其底层的V8引擎。V8引擎的优化,特别是针对性能抖动的优化,对于提升Node.js应用的稳定性和响应速度至关重要。

V8引擎新的编译器架构将编译器分为前端层、优化层和后端层。前端层生成由Ignition解释器运行的字节码,优化层通过TurboFan优化编译器提高代码性能。这种架构减小了性能抖动,提高了启动速度和基线性能。

性能抖动的一个主要原因是解释器和优化编译器之间的切换。为了避免这种情况,V8采用了Ignition解释器,它生成高度优化的小型解释器代码,执行指令并以低开销方式与V8 VM的其余部分进行交互。这种方式显著减少了内存使用,并提高了运行速度。

以下是一个简单的示例,展示了如何通过优化代码来减少性能抖动:

function add(v1, v2) {
  return {x: v1.x + v2.x, y: v1.y + v2.y, z: v1.z + v2.z};
}

// 使用相同类型的对象调用函数,以利用内联缓存
const ITER = 1e3;
let xsum = 0;
for (let i = 0; i < ITER; i++) {
  for (let j = 0; j < ITER; j++) {
    xsum += add({x: i, y: i, z: i}, {x: 1, y: 1, z: 1}).x;
  }
}

通过保持函数的输入类型一致,可以利用V8的内联缓存,从而减少优化和反优化的成本,进而减少性能抖动。

回到顶部