关于编程语言中的虚拟机

profile

Posted by bbkgl on January 5, 2020

伤心桥下春波绿

曾是惊鸿照影来

前段时间luajit的源码,然后在查阅资料的时候,经常会看到“虚拟机”,“字节码”等字眼。在luajit的源码中,也会经常看到vm等文件和函数。

20200112214812.png

实际上,虚拟机对于一门编程语言来说,就承担了执行“字节码/机器码”的工作。为什么要叫做虚拟机,重点就在于执行,模拟机器执行汇编指令的过程。

编译型语言和解释型语言

我太难了,明明写好了的,居然没提交上去,而且还没保存,只能重新写了。

常常见到各种帖子上说,C/C++,JAVA是编译型语言,诸多脚本语言如Python、Lua、JS是解释型语言。所以就很想知道到底什么叫编译及编译型语言,什么是解释及解释型语言。。。其实了解后我觉得Java更像解释型语言了2333,或者说两种都不算。

关于编译和解释:

  • 编译:指将目标(高级)语言编写的程序翻译成目标程序(二进制文件)的过程,通常经过过程有blablabla,这个不多说了,随便一查就有了。

  • 解释:运行时必需用解释器把程序一行一行执行,运行比较慢, 因为是运行时才把程序解析并执行. 优点是移植性,不同的机器只要有解释器就可以运行相同的程序。

这样其实就理解了编译型语言和解释型语言了:

  • 编译型语言编写的代码,经过编译后,由机器直接执行;解释型语言编写的代码,先转换成通用字节码后再由虚拟机执行。
  • 编译型语言编写的代码编译后因为可以直接执行,所以效率高,但和平台相关;解释型语言需要由虚拟机来执行,相当于间接由(编译型语言编写的)可执行程序来执行,所以肯定慢一些,但是因为虚拟机的间接和封装性,可以做到跨平台。

这个时候我又想到了一个问题,同样由虚拟机执行最后的代码,为什么Python和Lua可以热更新,而Java却不行呢?

其实Java的代码并不是直接由虚拟机执行的,而是先编译转换成.class的字节码文件,再通过虚拟机边解释边执行的。实际上不止是Java,LuaJit和Python其实也有这种执行方式,这里就不再细讲了。

从这里就引出了,虚拟机对于编程语言来说到底是什么?

编程语言中的虚拟机

虚拟机,就是“虚”的机器,虚拟的机器,没有实体。我理解,虚拟机就是一个正在运行的程序,这个程序的功能是按照对应的字节码/代码以及既定的规则执行对应的运算功能。所以就理解了为什么叫虚拟机了,既然很多高级语言无法直接控制CPU或者其他计算单元进行计算,那就找一个可以控制CPU等计算单元的代理,负责把高级语言想要表达的意思,转换成要执行的操作,虚拟机就是这个代理。(瞎说的)

所以,虚拟机要执行的是中间代码(字节码)。像Python或者Lua这种脚本语言,其实是先翻译成字节码,再由虚拟机执行,可以说是存在这个编译的过程的,并且可以显式地先编译再执行。所以很多人天天写Python,却不知道Python其实是可以编译的吧哈哈哈。

LuaJit是一个很特殊的存在,采用的是一种即时编译的方式,也就是说,有时候执行的不一定就是字节码,而是一种LuaJit自己定义的中间码(IR)。

20200112214921.png

这里我直接给图了,浅尝辄止,如果要深入了解Jit,我可能会再写一篇文章。

关于虚拟机的实现

虚拟机的实现,其实就是实现一个解释器中的执行器,完成解释器存在3个问题:

  • 设计一套字节码,分析源代码文件生成字节码。
  • 在虚拟机中执行字节码
  • 如何在整个执行过程中保存整个执行环境

以Lua为例:

20200112215037.png

Lua的解释器中,有一部分代码负责将Lua翻译成字节码,一部分执行字节码,这个过程是持续同步进行的。

当然了,我没有实现过虚拟机或者解释器,所以也不是很懂,这里只是基于我对阅读源码所分享的理解。