涡轮增压: JIT 编译优化

一图流

语言范式的根本矛盾和调和

编译型语言

  • 预先编译成机器相关的机器码(执行效率高)
  • 强类型支持静态内存布局(执行&内存效率高)
  • 函数调用采用固定偏移量寻址
  • 执行效率比解释器高 10 - 100 倍

解释型语言

  • 灵活
  • 访问属性需要哈希查找
  • eval 等特性导致无法预知的上下文污染
  • 闭包链管理开销

JIT 哲学

运行时类型特化

runtime Specialization

哲学本质:将动态类型转换为静态类型信息,在保证语言灵活性的前提下创造确定性的优化空间

隐藏类系统(Hidden Class)

  • 相同构造方式的对象共享隐藏类
csharp 复制代码
 // 构造器顺序决定隐藏类结构
function A() { this.x = 1; this.y = 2 }  // 隐藏类C1
function B() { this.y = 2; this.x = 1 }  // 隐藏类C2(与C1不同) 
  • 属性访问转换为固定偏移量查找
ini 复制代码
; 机器码示例(x64)
mov rax, [obj + 0x18]  ; 直接内存偏移访问

内联缓存(Inline Cache)

  • 记录最近10次调用点的类型信息
  • 生成特化的机器码片段
javascript 复制代码
function add(x, y) {
  return x + y; // 根据x,y类型生成特化代码
}
  • 单态调用(单一类型)速度接近C++
  • 多态调用(2-4种类型)性能下降50%
  • 超多态(5+类型)退化为哈希查找

投机优化

speculative Optimization

哲学本质:基于概率统计的预测执行,用空间换时间换取大概率性能提升

类型预测(Type Prediction)

ini 复制代码
 // 热代码段的类型假设
for (let i = 0; i < 1e6; i++) {
  sum += arr[i]; // 假设arr元素始终是SMALL_INTEGER
}
  • 生成带类型检查的机器码
ini 复制代码
cmp qword [rax], 0x1a3  ; 检查隐藏类
jne deoptimization      ; 跳转到去优化例程

分支预测(Branch Prediction)

  • 记录循环条件的历史走向
  • 预编译最可能的执行路径

典型案例:

sql 复制代码
 // 引擎会优先优化true分支
if (condition) { /* 执行概率90% */ } 
else { /* 10%概率 */ }

渐进式编译

tiered Compilcation

哲学本质:在编译开销与执行效率之间动态平衡,实现冷热代码区别对待

从解释到提前编译的升级过程(基于函数/循环的迭代次数判断是否编译)

  1. 解释执行,生成紧凑字节码(收集反馈信息)
  2. 基线编译器(baseLine)生成简单优化的机器码(编译耗时1ms内)
  3. 优化编译器(Trubofan) ,激进的进行优化(编译耗时 10 - 100ms)

去优化陷阱

deoptimization Bailout

哲学本质:承认预测可能失败,建立安全回退机制保障正确性

对于

  1. 属性类型突变
  2. 函数多态

会承认优化无效,抛弃优化代码。重建解释器

去优化 > 3 次则永久禁用优化

最佳实践

了解JS引擎的优化思路,以避免写出反优化的代码

经过高效优化的JS在浏览器中能够达到C++的70%以上

  1. 避免元素类型震荡

js 对于同种类型的数组会采用不同的内存格式策略

ini 复制代码
const arr = [1,2,3];         // PACKED_SMI_ELEMENTS
arr.push(4.5);               // → PACKED_DOUBLE_ELEMENTS
arr[2] = {};                 // → PACKED_ELEMENTS
  1. 避免动态属性破坏隐藏类
ini 复制代码
// 反模式代码
function createObj() {
  const obj = {};
  for (let i = 0; i < 10; i++) {
    obj[`prop${i}`] = i; // 每次迭代改变隐藏类
  }
  return obj;
}
  1. 使用类型稳定的数组和结构稳定的对象

笔者才疏学浅,各位读者多多担待,不吝赐教。

相关推荐
编程猪猪侠10 分钟前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞14 分钟前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路36 分钟前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失94938 分钟前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器
ReturnTrue86839 分钟前
Vue路由状态持久化方案,优雅实现记住表单历史搜索记录!
前端·vue.js
UncleKyrie44 分钟前
一个浏览器插件帮你查看Figma设计稿代码图片和转码
前端
遂心_1 小时前
深入解析前后端分离中的 /api 设计:从路由到代理的完整指南
前端·javascript·api
你听得到111 小时前
Flutter - 手搓一个日历组件,集成单日选择、日期范围选择、国际化、农历和节气显示
前端·flutter·架构
风清云淡_A1 小时前
【REACT18.x】CRA+TS+ANTD5.X封装自定义的hooks复用业务功能
前端·react.js
@大迁世界1 小时前
第7章 React性能优化核心
前端·javascript·react.js·性能优化·前端框架