本文共 2507 字,大约阅读时间需要 8 分钟。
专注于Java领域优质技术号,欢迎关注
作者:老曹撸代码
没错这又是一篇介绍 JVM 的文章,这类文章网上已经很多,不同角度、不同深度、不同广度,也都不乏优秀的。为什么还要来一篇?首先对于我来说,我正在学习 Java,了解JVM的实现对学习Java当然很有必要,但我已经做了多年C++开发,就算我用C++实现一个JVM,我还是个C++码农,而用 Java实现,即能学习 Java 语法,又能理解 JVM,一举两得。其次,作为读者,hotspot或者其他成熟JVM实现的源码读起来并不轻松,特别是对没有C/C++经验的人来说,如果只是想快速了解JVM的工作原理,并且希望运行和调试一下JVM的代码来加深理解,那么这篇文章可能更合适。
我将用Java实现一个JAVA虚拟机(源码在这下载:https://github.com/caoym/jjvm,加 Star 亦可),一开始它会非常简单,实际上简单得只够运行HelloWorld。虽然简单,但是我尽量让其符合 JVM 标准,目前主要参考依据是《Java虚拟机规范 (Java SE 7 中文版)》。
先写一个HelloWorld,代码如下:
我期望所实现的虚拟机(姑且命名为JJvm吧),可以通过以下命令运行:
接下来我们开始实现JJvm,下面是其入口代码,后面将逐步介绍:
我们将包含 main 入口的类称为初始类,JJvm 首先需要根据org.caoym.HelloWorld类名,找到.class 文件,然后加载并解析、校验字节码,这些步骤正是 ClassLoader(类加载器)做的事情。HelloWorld.class内容大致如下:
没错是紧凑的二进制格式,需要按规范解析,不过我并不打算自己写解析程序,可以直接用com.sun.tools.classfile.ClassFile,这也是用JAVA写好处。下面是HelloWorld.class解析后的内容(通过javap -v HelloWorld.class输出):
可以看到HelloWorld.class 文件中主要包含几部分:
以下为类加载器的部分代码实现:
类加载器可以加载两种形式的类:JvmOpcodeClass和 JvmNativeClass,均继承自JvmClass。其中JvmOpcodeClass 表示用户定义的类,通过字节码执行,也就是这个例子中的HelloWorld;JvmNativeClass表示JVM 提供的原生类,可直接调用原生类执行,比如 java.lang.System。这里把所有非项目内的类,都当做原始类处理,以便简化虚拟机的实现。
JVM规定入口是static public void main(String[]),为了能够查找指定类的方法,JvmOpcodeClass和JvmNativeClass都需要提供getMethod方法, 当然 main 方法肯定存在JvmOpcodeClass中:
下图为以HelloWorld的main()方法的执行过程:
下面将详细说明。
5.1. 虚拟机栈
每一个虚拟机线程都有自己私有的虚拟机栈(Java Virtual Machine Stack),用于存储栈帧。每一次方法调用,即产生一个新的栈帧,并推入栈顶,函数返回后,此栈帧从栈顶推出。以下为 JJvm中虚拟机栈的部分代码:
5.2. 栈帧
栈帧用于保存当前函数调用的上下文信息,以下为 JJvm 中栈帧的部分代码:
说明:
5.3. 方法调用
方法调用的过程大致如下:
以下为 JJvm 中的部分代码:
5.4. 解释执行字节码
字节码的执行过程如下:
以下为JJvm中解释执行字节码的部分代码:
Native方法的调用要更简单一些,只需调用已存在的实现即可,代码如下:
到目前为止,我们的“刚好够运行 HelloWorld”的 JVM 已经完成,完整代码可在这里下载:https://github.com/caoym/jjvm。当然这个JVM 并不完整,缺少很多内容,如类和实例的初始化、多线程问题、反射、GC 等等。我争取逐步完善JJvm,并奉上更多文章。
来源:https://www.jianshu.com/p/4d81465c2fb8
转载地址:http://xpfzx.baihongyu.com/