大牛程序员用Java手写JVM:刚好够运行 HelloWorld

  1. 前言

没错这又是一篇介绍 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 中文版)》。
2. 准备

先写一个HelloWorld,代码如下:
在这里插入图片描述
我期望所实现的虚拟机(姑且命名为JJvm吧),可以通过以下命令运行
在这里插入图片描述
接下来我们开始实现JJvm,下面是其入口代码,后面将逐步介绍:
在这里插入图片描述
3. 加载初始类

我们将包含 main 入口的类称为初始类,JJvm 首先需要根据org.caoym.HelloWorld类名,找到.class 文件,然后加载并解析、校验字节码,这些步骤正是 ClassLoader(类加载器)做的事情。HelloWorld.class内容大致如下:
在这里插入图片描述
没错是紧凑的二进制格式,需要按规范解析,不过我并不打算自己写解析程序,可以直接用com.sun.tools.classfile.ClassFile,这也是用JAVA写好处。下面是HelloWorld.class解析后的内容(通过javap -v HelloWorld.class输出):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到HelloWorld.class 文件中主要包含几部分:

常量池(Constant pool)
常量池中记录了当前类中用到的常量,包括方法名、类名、字符串常量等,如:#3 = String #23, #3为此常量的索引,字节码执行时通过此索引获取此常量,String为常量类型, 还可以是Methodref (方法引用)、Fieldref(属性引用)等。
方法定义
此处定义了方法的访问方式(如 PUBLIC、STATIC)、字节码等,关于字节码的执行方式将在后面介绍。
以下为类加载器的部分代码实现:
在这里插入图片描述
类加载器可以加载两种形式的类:JvmOpcodeClass和 JvmNativeClass,均继承自JvmClass。其中JvmOpcodeClass 表示用户定义的类,通过字节码执行,也就是这个例子中的HelloWorld;JvmNativeClass表示JVM 提供的原生类,可直接调用原生类执行,比如 java.lang.System。这里把所有非项目内的类,都当做原始类处理,以便简化虚拟机的实现。
4. 找到入口方法

JVM规定入口是static public void main(String[]),为了能够查找指定类的方法,JvmOpcodeClass和JvmNativeClass都需要提供getMethod方法, 当然 main 方法肯定存在JvmOpcodeClass中:
在这里插入图片描述
5. 执行非 Native(字节码定义的)方法

下图为以HelloWorld的main()方法的执行过程:
在这里插入图片描述
我自己是一名从事了5年前端的老程序员,辞职目前在做讲师,今年年初我花了一个月整理了一份最适合2019年学习的web前端干货,从最基础的HTML+CSS+JS到移动端HTML5到各种框架都有整理,送给每一位前端小伙伴,可以加入我的QQ学习交流群:751196913 这里是小白聚集地,欢迎初学和进阶中的小伙伴

猜你喜欢

转载自blog.csdn.net/QIQI12356/article/details/89195683