Java虚拟机非常复杂,要想真正理解它的工作原理,最好的方式就是自己动手写一个。但是这个系列的定位还是入门,所以有很多的东西暂时都不会实现,比如 malloc,GC,多线程,native interface等。主要的目的还是在于大致了解JVM是一个什么样的东西,这也是我采用java来实现JVM的一个原因,便于理解。
由于我之前也实现过一个简单的可以执行汇编的模拟器,写这个对我来说不难,但是可能出现有些地方我认为理所当然,而刚接触的读者很难理解的情况。如果出现了,欢迎大家在原博客中评论。
下面是原始博客的地址:
该项目的地址:
项目的完成度现在在90%左右了,运行一些简单的类是没有问题的,后面会慢慢扩展。
该系列的文章会对项目的代码进行详细的介绍。这个系列大致会分为下面几个部分,:
  1. 实现 classpath,暂时只兼容 windows,有兴趣参与进来的可以提pr
  1. 实现 class 文件的解析
  1. 实现运行时数据区
  1. 实现解释器,解释 method 中的指令
  1. 实现类与对象的支持
  1. 实现方法调用
  1. 实现数组
  1. 实现异常
该项目并不会去实现对象分配与内存管理,有兴趣的可以看看 csapp 的 malloc lab。
项目的参考资料:
  • 《自己动手写Java虚拟机》,作者使用go语言实现。
  • 官方文档
  • 其他类似的开源项目等

虚拟机介绍

notion image
看上图,类加载子系统将 class 文件加载到内存中,这个过程需要完成2件事:
  • 找到 class 文件的路径
  • 将 class 文件按照格式解析
这篇文章,主要是完成第1件事,寻找 class 文件。

类路径

Java虚拟机规范并没有规定虚拟机应该从哪里寻找类,所以我们可以自由一点。但是回想一下,java 加载类的时候,它通过双亲委派机制来加载类,所以类路径至少有3个:
  • 启动类路径(bootstrap classpath),路径默认对应jre\lib目录
  • 扩展类路径(extension classpath),路径默认对应jre\lib\ext目录
  • 用户类路径(user classpath),路径的默认值是当前目录
在 windows 上,这些路径都可以通过 JAVA_HOME 拿到。

搜索类

有了类路径,我们就可以在这些路径下面搜索指定的类了。搜索会发生以下几种情况:
  • class 文件是一个单独的文件,在当前目录下
  • class 文件是一个单独的文件,在当前目录的子目录里面
  • class 文件在压缩文件里面
根据这些情况,我们使用组合模式来写代码,看以下组合模式的类图:
notion image
我们仿照这个类图,首先定义一个接口:
这里的参数格式需要注意,是全限定类名的形式。

DirEntry

我们先实现最简单的搜索情况.
由于类文件是在当前路径下,所以我们直接读取文件流就好了。
 

ZipEntry

读取当前目录下的 zip 文件里面的内容,稍微麻烦点,但是我们有新的api,所以代码也不多。
 

CompositeEntry

notion image
在程序的运行时,我们可以设置 -cp 参数,指定用户类路径,它可以利用; 来配置多个路径。
整个逻辑简单,就是根据; 分割路径,然后分别做解析,然后创建对应的 Entry:
 

WildcardEntry

假如说我们需要加载 java/lang/String.class,该类在xxxx/Java/jdk-1.8/jre/lib的 rt.jar 里面:
notion image
但是我们最好不将类路径写死,所以可以采用通配符的方式。比如我想加载jre/lib 下的类,那么就可以指定为 jre/lib/*,这种写法会加载当前目录下所有 JAR文件。
实现也很简单,就是将 jre/lib 下的所有 jar 文件过滤出来,使用 ;拼接后就是一个 CompositeEntry 了。
 

Classpath

经过上面的步骤,我们类的搜索做完了,现在我们需要指定下面的三个路径:
  • 启动类路径(bootstrap classpath),路径默认对应jre\lib目录
  • 扩展类路径(extension classpath),路径默认对应jre\lib\ext目录
  • 用户类路径(user classpath),路径的默认值是当前目录

JRE路径

从系统设置的环境变量里面去读取。

启动类路径

注意看,我们这里添加了通配符,这样就可以遍历该目录下的所有 jar 文件。

扩展类路径

同上。

用户类路径

该路径默认为当前目录,如果命令行里面有设置,那就读取命令行里面的参数。命令行的实现这里不展开,有很多库可以实现命令行参数的解析。
 

读取类

有了上面的框架,我们就可以开始读取一个类了:
由于我们加载类的时候,传递的类名是不带后缀的,所以需要先加上,然后再搜索。
 

结语

本章讨论了Java虚拟机从哪里寻找class文件,对类路径有了较为深入的了解,并且把抽象的类路径概念转变成了具体的代码。下一章将研究class文件格式,实现class文件解析。
    Loading...