同一粒种子——图灵 1936 年的一纸证明——长成两棵树。按年份生长,点枝收展。
树讲的是「谁架在谁之上」;这条流水线讲的是「源码一步步变成能跑的东西」。真正的区别不是「解释 vs 编译」,而是 分发物(源码 / 字节码 / 机器码)× 运行时是否 JIT——三条路由此分叉。
整条横着铺开(可往右拖):源码 → 三条路(编译原生 / 字节码·纯解释 / 字节码·解释+JIT)→ 三条线汇到「代码段」→ 进程虚拟地址空间 → OS 分页 → CPU / 物理内存。
宏观上所有语言同一条路;差别在「各自怎么处理」。关键一问:这个进程到底是谁——是程序本身,还是一台虚拟机(JVM / CPython / V8)把程序代码当数据加载进来跑?点标签切语言。
上面讲每种语言各自怎么跑;下面四块是它们共用的底层机器——点标签切换。
字节码语言的「VM」说白了就是一个普通的原生程序(它的机器码在进程的 .text)。它的心脏是一个循环:取一条字节码 → switch 跳到这条 opcode 的处理逻辑——源码里是一段 C 函数,但构建解释器时就已经 AOT 编成机器码、躺在 .text 里 → CPU 执行这段现成机器码 → 取下一条。字节码只是被它读取的数据。
// 解释器的心脏(简化) for (;;) { op = *pc++; // 取下一条字节码 switch (op) { case LOAD: push(local); break; case ADD: push(pop()+pop()); break; case CALL: call_func(); break; // …每条 opcode 对应一段处理代码(构建解释器时已编成机器码) } }
实线=冷 / 解释路径(字节码被解释器逐条解释、解释器本身也在 CPU 上跑);虚线=热代码路径(数到热点 → 触发 JIT → 以字节码为输入编成机器码 → 这段热机器码直接在 CPU 上跑)。
HotSpot 里有三套执行引擎:一个字节码解释器负责解释,两个 JIT(C1、C2)负责编译。方法越热,待遇越高;所有编译产物都进 Code Cache。
前端只管读懂源语言,后端只管生成某个 CPU 的指令,中间靠 IR(中间表示) 解耦。字节码语言的 javac 也是编译器——只是它的"后端"停在字节码,真正的 codegen 推迟到运行期的 JIT。
每个源文件单独编成目标文件 .o(含「我用了 printf 但不知道它在哪」的未决符号)。链接器把这些符号和库里的实现对上、合并成一个整体。
.a)直接拷进可执行文件.so/.dll)机器码里写的是虚拟地址。经典 x86 保护模式走完整三段:逻辑地址 →(分段)→ 线性地址 →(分页)→ 物理地址。让两个进程用相同的虚拟地址,看它们各自落到不同物理页帧。
mov eax, [0x08048000]mov eax, [0x08048000]CS:0x08048000),段选择子指向描述符表某一项。AI 系统的完整分层(对应《AI 系统:原理与架构》表 1.3.1)——从「用 AI 解决什么」一路落到硅片。自上而下五层:领域应用 → 开发体系 → 框架 → 编译器 → 芯片。