jit在运行时动态编译热点代码并持续优化,aot在执行前完成全部编译以实现快速启动;前者适应性强但冷启慢,后者启动快但缺乏运行时优化能力。

运行时编译(JIT)和预编译(AOT)是两种根本不同的代码执行优化路径:前者在程序启动后、真正要执行某段代码时才编译,后者则在安装、打包或首次启动前就完成全部编译。
运行时编译(JIT):边跑边优化
JIT 编译器不提前生成机器码,而是等程序运行起来、发现某段代码被频繁调用(称为“热点代码”)后,再把它动态编译成当前 CPU 能直接执行的本地指令。比如 Java 的 HotSpot、.NET 的 CLR、JavaScript 引擎 V8 都依赖 JIT 来提升长期运行的性能。
- 优势明显体现在持续运行的场景:能根据真实运行数据做深度优化,如方法内联、循环展开、基于类型假设的投机优化
- 支持跨平台分发:一份字节码可在不同系统上由各自的 JIT 编译器生成适配的机器码
- 开发调试友好:Halide、Python 3.14 等工具默认启用 JIT,改完逻辑立刻重编译执行,省去重新打包环节
- 代价是冷启动延迟:首次执行热点路径前需等待编译,可能影响响应敏感型应用(如 CLI 工具、短生命周期脚本)
预编译(AOT):一次编译,随处运行
AOT 在构建阶段就把源码或中间表示(如 IL、字节码)直接转为特定平台的原生机器码,生成可直接加载执行的二进制文件。Go(实验性)、.NET 的 ReadyToRun、Java 的 GraalVM Native Image 都属于这一类。
- 启动极快:跳过运行时编译环节,进程一加载就能执行,适合 CLI、微服务冷启、嵌入式或移动端
- 内存更可控:没有 JIT 编译器本身及其元数据的运行时开销,堆外内存占用更稳定
- 牺牲的是运行时适应性:无法根据实际输入、硬件缓存状态或分支走向做二次优化;跨平台需分别构建
- 部分 AOT 实现(如 .NET 6+ ReadyToRun)会保留部分元数据,供运行时做轻量级再优化,但远不如 JIT 灵活
混合编译:兼顾冷启与长稳性能
现代主流平台正转向 JIT + AOT 协同的混合模式。典型做法是:基础框架和启动逻辑用 AOT 编译保证秒级启动;核心计算模块(如图像处理 pipeline、数值仿真循环)标记为 JIT,在运行中识别热点并深度优化。
- .NET 分层编译就是代表:第一层用 AOT 或快速 JIT 快速出码,第二层后台线程对高频方法做高阶优化
- Go 1.21+ 支持
//go:compile(jit)注解,只对关键函数启用运行时重编译,避免全局 JIT 开销 - Python 3.14 提供
baseline/opt/maxopt三级策略,允许按函数粒度控制 JIT 深度
怎么选?看你的项目节奏和瓶颈
不用纠结“哪个更好”,而要看你最不能妥协的是什么:
- 如果是 Web API、长时间驻留的服务、AI 推理后端——优先 JIT 或混合策略,让性能随运行时间增长
- 如果是命令行工具、Serverless 函数、桌面客户端首屏——AOT 或带 AOT 基础的分层编译更稳妥
- 如果处于快速迭代期(如算法原型、教学演示),JIT 的即时反馈价值远超几毫秒启动损耗
- 若部署环境受限(如无写权限、无 JIT 所需的 mmap 内存区域),AOT 是唯一可行路径











