V8 发布了 8.0 版本,此版本除了修复一些
bug,毫无疑问又带来了性能的提高。目前是预览,正式版将于几个星期后随 Chrome
80 Stable 一起发布。

时间: 2019-12-09阅读: 7标签: 引擎

澳门新葡萄京官网首页 1

Google 最新发布了 V8 JavaScript 引擎 V8 8.0 ,其中使用压缩指针(pointer
compression)技术,在不影响性能的情况下实现堆内存占用降低了
40%。此外,V8 8.0 添加了支持“可选链”(optional chaining)的操作符?.
,以及支持“空合并”(nullish coalescence )的双问号操作符?? 。V8 v8.0
将正式提供在 Chrome 80 版本中。

性能改进

先看看性能改进,这包括内存占用减少与速度提升:

指针压缩

V8
堆包含整个项目所有东西,例如浮点值、字符串字符、编译的代码和标记值(tagged
values),标记值代表指向 V8
堆的指针或小整型,开发团队发现这些标记值占据了堆的大部分空间。

标记值与系统指针一样大,对于 32 位架构来说,它们的宽度为 32 位,而在 64
位架构中,则为 64 位。在将 32 位版本与 64
位版本进行比较时,为每个标记值使用的堆内存是原来的两倍。

此版本通过一个方法减小了这一块内存:指针压缩。因为高位可以由低位合成,只需要将唯一的低位存储到堆中即可节省内存资源,经过测试,平均节省了
40% 的堆内存。

澳门新葡萄京官网首页 2

通常在减少内存的同时,也会牺牲速度性能,但是经过这一改进,V8
及其垃圾收集器中,都能够看到真实网站性能的提升。

澳门新葡萄京官网首页 3

优化高阶内置程序

此版本消除了 TurboFan
优化管道中的一个限制,该限制阻止了对高阶内置函数的优化。

const charCodeAt = Function.prototype.call.bind(String.prototype.charCodeAt);

charCodeAt(string, 8);

charCodeAt
对 TurboFan 的调用是完全不透明的,从而导致生成对用户定义函数的通用调用。通过此更改,现在可以识别出实际上是在调用内置 String.prototype.charCodeAt 函数,从而能够触发
TurboFan
库存中所有的进一步优化来改善对内置函数的调用,进而获得与以下代码相同的性能:

string.charCodeAt(8);

据 V8 核心成员 Leszek Świrski 介绍,V8 v8.0 对 JavaScript 标签值(tagged
value)做了压缩处理。标签值用于表示指向堆或小整数的指针。对于 64 位
CPU,V8 指针并未使用整个 64
位字节表示,而是仅使用了其中的低位字节,高位字节通过算法合成。V8
团队在文档中详细阐述了指针压缩算法,该算法参考了Java等平台目前在用的技术。在
InfoQ 的访谈中,Świrski 阐明 V8 v8.0
中使用的内存压缩算法去除了内存地址的头 32 位,强制“压缩”指针到 4GB
空间中,所有“压缩”指针构成 4GB
空间内的相对偏移量。在计算完全指针地址时,需要在压缩指针地址上添加基础偏移量。Świrski
补充说明,团队计划结合使用多字节字对齐和地址层位偏移的方式,将压缩的堆规模扩展到
4GB
以外的空间。其算法的基本理念是将内存地址逻辑上组织到多字节字(word)而非字节中。例如,如果使用
8 字节的字,那么只需将地址表示为从 0、7、15、23
等开始,因此能够实现地址空间扩展到 23*232 字节。

JavaScript

JavaScript 特性方面也有所变化,带来了两个新特性:

Optional Chaining

在编写属性访问链时,开发者经常需要检查中间值是否为空(null 或
undefined),这样可能会写出很冗长的显式错误检查链。

// Error prone-version, could throw.
const nameLength = db.user.name.length;

// Less error-prone, but harder to read.
let nameLength;
if (db && db.user && db.user.name)
  nameLength = db.user.name.length;

Optional
Chaining(?.)使开发者可以编写更可靠的属性访问链,以检查中间值是否为空。如果中间值是空值,则整个表达式的计算结果为
undefined。

// Still checks for errors and is much more readable.
const nameLength = db?.user?.name?.length;

同时,除了静态属性访问之外,Optional Chaining 还支持动态属性访问和调用。

null 合并(Nullish Coalescing)

另一个与 Optional Chaining 很接近的特性是 null 判断合并(Nullish
Coalescing),由特定的 Nullish Coalescing 操作符 ??
启用,它是一个新的短路二元运算符。

现在有时会使用逻辑 || 运算符处理默认值,例如:

function Component(props) {
  const enable = props.enabled || true;
  // …
}

运算 a || b,当 a 为非真时结果为 b,如果 props.enabled
本身显式设置为“false”,那么这样的运算还是会得到第二个运算数“true”,也就是
enable = true。

现在使用 null 合并运算符 ??,当 a 为空,也就是 null 或者 undefined 时,a
?? b 的运算结果为 b,否则为
a,这样的默认值处理行为才是符合逻辑的,弥补了前边讲到的问题。

function Component(props) {
  const enable = props.enabled ?? true;
  // …
}

同时,null 合并运算符和 Optional Chaining
是辅助功能,可以很好地协同工作。它们可以进一步处理上述示例中没有任何
props 参数传入的情况。

function Component(props) {
  const enable = props?.enabled ?? true;
  // …
}

此外,API 有一些变化,可以通过以下方式查看:

git log branch-heads/7.9..branch-heads/8.0 include/v8.h

更新说明:

(文/开源中国)    

V8
团队特别指出,压缩指针向全指针的转换本身是非常高速的操作,因此压缩指针技术并未引入额外的性能代价。而另一方面的额外收益是,经压缩的指针使得
V8 垃圾回收机制更为高效。初步基准测试表明,在 Facebook、CNN、Google Maps
等网站的实践应用中,V8 v8.0
无论是在移动端还是在桌面设备端都表现得更为快速。

从 JavaScript 语言方面看,V8 v8.0 引入了对“可选链”(optional
chaining)和“空合并”(nullish coalescence)两种有用语言特性的支持。

可选链技术意在简化属性值的依次访问运算。由于一些中间对象是null或undefined,运算存在抛出异常的风险。例如,在下面的代码中,为避免发生上述问题,需预先检查所有需访问的中间属性是经过良好定义的:

if(resourceresource.addressresource.address.types)returnresource.address.types.length

使用可选链操作符?.,该代码可替换为如下代码。其中确保了一旦中间组件出现null或undefined等问题,整体表达式立刻做出短路处理:

returnresource?.address?.types?.length

对于空合并操作符??,在如下代码的使用场景中,进一步优化了操作符||:

letiterations= settings.iterations||4;

||操作符的不足之处在于,上面的代码中,当所需设置的settings.iterations取值为false(即settings.iterations
== 0)时,不能使用||操作符。运算最终依然得到默认值,即4。空合并操作符??
将会正确处理这类问题。例如:

let iterations= settings.iterations??4;

上例中,a是null或undefined时,运算a ?? b取值为b,否则取值为a。

V8 v8.0 目前依然尚未形成 V8 稳定发行版,计划在数周后发布在 Chrome 80
稳定版中。开发人员可使用git checkout -b 8.0 -t
branch-heads/8.0命令获取该版本。

2019 年 12 月 23 日更新:添加了 Leszek Świrski 对 V8
中实际采用的指针压缩算法的阐述。

原文链接:

V8 JavaScript Engine 8.0 Reduces Heap by 40%, Adds Optional Chaining and
Null Coalescing