前端性能优化手册JIT与GC优化
JIT与GC优化
JIT与GC优化
untyped(无类型)。
JAVASCRIPT是个无类型的语言,这导致了如x=y+z这种表达式可以有很多含义。
y,z是数字,则+表示加法。y,z是字符串,则+表示字符串连接。而JS引擎内部则使用“
细粒度”的类型,比如:
- 32-bit* integer。
- 64-bit* floating-point。
这就要求js类型-js引擎类型,需要做“boxed/unboxed(装箱/解箱)”,在处理一次
x=y+z这种计算,需要经过的步骤如下。
- 从内存,读取
x=y+z的操作符。- 从内存,读取
y,z。- 检查y,z类型,确定操作的行为。
unbox y,z。- 执行操作符的行为。
box x。- 把
x写入内存。只有第
5步骤是真正有效的操作,其他步骤都是为第5步骤做准备/收尾,JAVASCRIPT的untyped特性很好用,但也为此付出了很大的性能代价。
JIT。
先看看
JIT对untyped的优化,在JIT下,执行x=y+z流程。
- 从内存,读取
x=y+z的操作符。- 从内存,读取
y,z。- 检查
y,z类型,确定操作的行为。unbox y,z。- 执行 操作符 的行为。
box x。- 把
x写入内存。其中
1,2步骤由CPU负责,7步骤JIT把结果保存在寄存器里。但可惜不是所有情况都能使用JIT,当number+number,string+string等等可以使用JIT,但特殊情况,如:number+undefined就不行了,只能走旧解析器。- 新引擎还对“对象属性”访问做了优化,解决方案叫
inline caching,简称:IC。简单的说,就是做cache。但如果当list很大时,这种方案反而影响效率。
Type-specializing JIT
Type-specializing JIT引擎用来处理typed类型(声明类型)变量,但JAVASCRIPT都是untype类型的。
Type-specializing JIT的解决方案是:
- 先通过扫描,监测类型。
- 通过编译优化(优化对象不仅仅只是“类型”,还包括对JS代码的优化,但核心是类型优化),生成类型变量。
- 再做后续计算。
Type-specializing JIT的执行x=y+z流程:
- 从内存,读取
x=y+z的操作符。- 从内存,读取
y,z。- 检查
y,z类型,确定操作的行为。unbox y,z。- 执行操作符的行为。
box x。- 把
x写入内存。代价是:
- 前置的扫描类型
- 编译优化。
所以·Type-specializing JIT·的应用是有选择性,选择使用这个引擎的场景包括:
- 热点代码。
- 通过启发式算法估算出来的有价值的代码。
另外,有2点也需要注意:
- 当变量类型 发生变化时,引擎有2种处理方式:
- 少量变更,重编译,再执行。
- 大量变更,交给JIT执行。
数组,object properties, 闭包变量 不在优化范畴之列。