Python与Java的字节码和虚拟机

个人知识库

Author: 刘杰文, Date: 2023-08-09 17:23:00 +0800, Categories: , Tags:

Python与Java的字节码和虚拟机

这件事其实是很多人想复杂了,其实逻辑还是很简单很初始的样子。

为了弄明白这件事,我查阅了一些网络资料:

  1. https://blog.csdn.net/weixin_44337445/article/details/111602975
  2. https://zhuanlan.zhihu.com/p/58167547

Quick Section Reference

  1. Bytecode(字节码)
  2. Virtual Machine(虚拟机)

正文

两个东西其实应该一起讲,因为它们基本就是一个事情,不过为了直接回答我们的问题,我将分两部分讲解。

字节码

事实上,大部分高级语言在转换到机器可执行的具体机器码前,都会经过一种中间语言。比如C++,编译器首先会把代码编译成汇编语言,然后再进行下一步。而这个中间语言,在Java和Python这里,其实就是字节码的语言,这些代码被转换成字节码,然后进行下一步。

有说法是,编译型语言就是有显示的编译过程,解释型语言一般是本身可以执行。这个说法已经过时了。比如Java,虽有用javac进行编译的操作,但是现在也能直接执行本身了,据说这是在Java11加入的特性。再说说Python,python得到字节码的方式也是编译,只是很多时候无感罢了。这件事有个更好的角度,就是从语言是静态还是动态来分类。

在将语言是静态还是动态前,我们首先要明确一个概念,语言分强类型和弱类型,python和java都是强类型。虽然我们在使用python的时候似乎可以很随意地改变一个对象的类型,但是其本身在运行时是有检查类型的。 这件事,是运行时环境替你做的脏活累活,这部分放在下面虚拟机部分理解。

Java是明确了数据类型才进行编译的,因此它的字节码文件中包含数据类型的信息,也就不可更改。而python是不用开发者明确数据类型的,因此它的字节码文件中是不包含相关的数据类型的,但是它在运行时又需要明确数据类型,而这件事就是运行时环境替你做的工作,它会自己去推测。所以,python是动态语言,而Java是静态语言,因此虽然都有用虚拟机的过程,但大体上感觉起来就成了:python是解释型语言,边运行边解释,Java是编译语言,直接运行不用解释。但是这件事,同样放到下面虚拟机部分讲。

那为什么会有字节码呢?这就是为了兼容不同平台而设计的策略,字节码本身应该等同机器码,只不过这个机器是对应相同的一个机器:虚拟机。

虚拟机

首先要明白,虚拟机可以分成两类:一类是“系统虚拟机”,另一类是“程序虚拟机”。前者就是用例如VMware, Virtual Box之类的工具运行的,后者其实更多地应该被理解成“运行环境”。

程序虚拟机会给一个程序建立一个独立的环境以供运行,在启动程序前启动,在结束程序后结束。

而不管是Java还是Python,其实都是编译成它们对应的虚拟机上的机器码。这个虚拟机的机器码,就被叫做“字节码”。这个名称的来源,也跟它是按字节储存信息有关,不过这不是这里的重点。

字节码是可以直接在相应语言的虚拟机上运行的,而作为“机器码”,它也可以被反编译成汇编语言。比如python的.pyc字节码文件,它就可以被反编译回汇编语言,文件扩展名为.opcode,里面储存的都是对虚拟机的操作指令。

而为什么这些语言都编译成一个字节码文件就可以在不同平台通用呢?因为它们并不是真的在不同平台通用,它们本身在各个平台甚至根本不能运行,能运行它们的一直只有它们的虚拟机。所以这件事就很简单了,就是有人为不同平台实现了同一款虚拟机,而这些虚拟机运行字节码,就相当于这些平台运行了程序的效果。

所以事情很明显了,从虚拟机上指令到物理机上的指令之间发生了转换,不同实现进行了不同转换,所以其实转换本身就是一个解释的过程。虚拟机会把代码一行行解释成能运行的指令,所以有虚拟机就是有解释这个过程。

总结

  1. 现在在试图明确区分一门语言是解释型语言还是编译型语言有时可能是不明智的。有时已经不那么明显了,有种说法是:现代的解释器包含了编译器和虚拟机。现代的发展使得这个分类的界线越来越模糊。
  2. 它们都有编译的过程,也都有解释的过程。粗浅地理解,它们本身可以是编译型,而解释发生在虚拟机上。至于为什么Java常用“虚拟机”术语而python常用“解释器”术语,其实更多的是从表象来看了。

拓展阅读

此部分为引用。

通过JVM和解释器的概念澄清,似乎还是不明白为啥JVM就被称为虚拟机,JVM中有运行的是字节码,它可能直接被解释执行,也可能被再次编译成目标语言,Python中的解释器也会先预编译Python代码为字节码,再解释执行。那么到底有啥区别?

很多人参与了讨论,分别从不同的角度去阐述区别。

有人认为虚拟机是和语言无关的,JVM为例,除了Java之外,Scala,Clojure,甚至Python借助于Jython工具,也可以运行在JVM上,而没听说什么语言能有Python解释器解释执行,除了Python。

也有人从语言的类型上,Java为静态类型的语言,而Python为动态语言。这使得Java字节码既可以被解释执行也可以被编译成机器指令再执行。而Python则复杂多了,它虽然让程序员可以不去关注变量的类型,但解释器不得不去推断数据类型,这一定程度上影响性能。

还有观点认为解释器是一个历史遗留术语,现代语言中虚拟机和解释器的分界已经很模糊甚至不存在。

事实上,笔者在《Learning Python》一书中,看到把作者把Python的解释器称为PVM,基于这个事实来讲,本人更认同的是解释器和虚拟机的区别正在越来越小,已经是我中有你,你中有我的地步。独立的分割来看,可能还能区分这几步是解释器行为,这几步是虚拟机的行为,但是作为一个整体来看,两者的区别确实没那么明显

发布于 2019-03-03 11:56