虚拟机架构
虚拟机(VM)执行 Lua 代码,把源码转换成机器可以执行的操作,是 Lua 高效运行的核心部分。
1. 字节码
字节码是 Lua 代码的中间表示,介于源代码和机器码之间,供虚拟机解释执行。源代码在执行时先被编译成字节码,编译经过词法分析、语法分析和代码生成三个阶段。字节码指令集由一组简洁的指令组成,每条指令对应一种操作,便于虚拟机快速解析和执行。
2. 虚拟机执行器
执行器读取并执行字节码指令,是 Lua 运行时的核心。主循环在 lvm.c 的 luaV_execute 中:读取指令、解码、执行操作,并处理相关的数据。Lua 的虚拟机基于寄存器,指令直接以寄存器编号读写操作数,寄存器实际是从 Lua 栈中为当前函数划分出来的一组槽位。
3. 堆栈管理
栈是执行函数调用、局部变量和表达式计算的关键数据结构。每次函数调用都在栈上分配一段连续的槽位作为自己的“寄存器”,字节码指令通过寄存器编号获取和存储操作数,而不是像 JVM 那样反复压栈、弹栈,因此指令数更少、分支预测更友好。每个函数调用还对应一个调用信息结构(CallInfo),记录函数的参数、局部变量所在的寄存器区间以及返回地址。
4. 内存管理
虚拟机内置垃圾回收机制自动管理内存。Lua 默认使用增量式标记-清除算法(5.4 也可切换到分代模式),定期扫描内存,标记活跃对象并清除不再使用的对象。创建虚拟机时通过 lua_newstate 注册一个统一的分配函数(lua_Alloc),所有对象的分配与释放都经由它完成,默认实现基于 realloc,并不使用预分配的内存池。
5. 调用机制
每次函数调用时,虚拟机创建一个新栈帧压入调用栈,函数返回时弹出栈帧、恢复到调用点,嵌套调用和递归调用都走这条路径。参数通过堆栈传递,调用和返回时由虚拟机处理参数传递和返回值。
6. 调试和扩展
调试接口配合调试库和工具进行调试和分析。C API 允许用 C 语言编写扩展,修改虚拟机行为,或与 Lua 进行交互。
总结
字节码作为中间表示、基于寄存器的栈管理、统一的分配函数、栈帧式的调用机制,这套设计以性能和简洁性为目标;调试接口和 C API 则把扩展能力留给了宿主程序。