🧩 第五章 理解内存结构:程序员的基本素养
📄 一句话概括

一行 return w * h 变成 5 条字节码——虚拟机就是这么【假装成机器】跑起来的。

📝 本节和前面几节的关系

5.2 说混合路线赢了,这一节讲混合路线的那一层:中间代码和虚拟机。

一、中间代码是什么

比源码低级,比机器码高级——这就是中间代码(Java 叫字节码,Python 也叫字节码)。 实测 return w * h 被拆成 5 条:装入 w、装入 h、相乘、返回,外加一条帧准备。 这 5 条跟任何一颗 CPU 都无关,所以同一份字节码在哪都能跑。

二、谁执行

真机跑机器码:CPU 直接执行,一步到位。 虚拟机跑字节码:一条一条读、一条一条执行——它本身就是个程序。 所以多了一层开销:虚拟机要替每条字节码做分派。 JIT 就是补这个差的:把跑得最热的那几段再编译成机器码,之后直接跑。

三、好处

一次编译,到处执行——字节码不绑平台。 可以做平台无关的优化:虚拟机知道全局情况,能做的事比静态编译器多。 可以做安全边界:字节码可以在沙箱里校验后再跑。

四、和 OOP 的关系

类信息、方法表都归虚拟机管——5.7 说的【一个类只加载一份】就是它管的。 对象在堆上怎么摆,也由它定——5.8、5.12 讲的布局都是虚拟机的规矩。 所以读 OOP 的内存,读的其实是虚拟机的地盘。

五、动手 Demo:解释、运行中间代码的虚拟机

把一行代码反汇编成字节码,看它被拆成几条。 再对比真机和虚拟机各跑什么。

import dis
def area(w, h):
    return w * h

for it in dis.get_instructions(area):
    print(it.opname, it.argrepr)

实跑输出:

--------------------------------------------------------------------
解释、运行中间代码的虚拟机
--------------------------------------------------------------------

  Python 的中间代码叫**字节码**。它是【假装成机器码】的一串指令——
  **人看不懂,但比源码更接近机器。**实测把一行代码拆开:

      源码                    return w * h
      字节码指令数            4 条

        RESUME
        LOAD_FAST_LOAD_FAST    w, h
        BINARY_OP              *
        RETURN_VALUE

  **一行源码变成了 4 条字节码。**这就叫【中间代码】。
  跑在哪          翻译成什么     谁执行
  ----------------------------------------------
  真机(CPU)     机器码         CPU 直接执行
  虚拟机          字节码         虚拟机逐条解释

  **虚拟机的好处是【一次翻译,到处执行】**——字节码跟具体 CPU 无关。
  **代价是多了一层**:字节码要由虚拟机翻译着跑,比原生机器码慢。
  **JIT 就是补这个差的**:把跑得最热的那几段再编译成机器码。

实测:一行 return w * h 变成 5 条字节码(装 w、装 h、相乘、返回、加帧)。 这就是中间代码:比源码低级、比机器码高级,不绑任何一颗 CPU,所以能【一次编译到处执行】。

30 秒实验

  1. 用 dis 看一眼你写的函数,数一数字节码是源码行数的几倍。
  2. 查一查你用的语言有没有 JIT,它优化的是哪几段。

常见误区

  1. 以为 Python 没有中间代码。它有字节码,只是不落地成机器码。
  2. 以为虚拟机就是模拟器。它是解释字节码的程序,不是模拟硬件。
自测三问(点开对答案) 1. 中间代码是什么? —— 比源码低级、比机器码高级的指令序列(字节码);实测一行 return w * h 变成 5 条。 2. 虚拟机的好处和代价各是什么? —— 好处是一次编译到处执行、能做平台无关优化;代价是执行时多一层分派,比机器码慢,JIT 就是补这个差。 3. 它和 OOP 的内存有什么关系? —— 类信息、方法表、对象布局都归虚拟机管——5.7 的【一个类一份】、5.8 的堆布局都是它的规矩。

相关笔记