哈喽,大家好,我就是明明可以靠脸吃饭,却偏偏抢大家饭碗的硬核男人子牙老师。

本篇文章是专栏《用Java带你手写JVM》的第二篇。画人画皮先画骨,本篇文章咱们的目标是实现JVM框架,输出hello world。

是不是完全不知道代码怎么写?是不是就像当初学会Java不知道怎么做东西的感觉是一样的?这就是我说的虚拟机思维。把我这套课程跟完,把练习做做,慢慢地,你就有了虚拟机思维。这种思维对于你研究Hotspot或其他虚拟机,是非常非常非常有帮助的!


课程目标

本篇文章咱们要学习的目标就是在我们自己实现的JVM上成功运行这段Java代码

java手写笔记 手写jvm_java手写笔记


看下运行结果


java手写笔记 手写jvm_java手写笔记_02


前置知识

这部分很重要!很重要!很重要!

先说下JVM是如何运行这个Java程序的:

  1. JVM启动并完成初始化。Hotspot初始化做的事情很多很多,这里不细讲了。我之前研究的时候画了JVM启动流程图,需要的小伙伴可以关注公众号【硬核子牙】回复【JVM启动流程图】获取
  2. 完成类加载器的创建,然后去找main方法所在的类
  3. 触发加载阶段将硬盘上的字节码文件载入内存,进行解析,生成klass对象
  4. 根据方法名及方法描述符,在这个klass对象中找到main方法
  5. 构建方法运行环境
  6. 调用方法
  7. 调用完清理环境

你可以这样说,JVM是由五大模块组成:内存模型、类加载器子系统、执行引擎、垃圾收集器、JIT。JVM运行任何一个Java程序,除了垃圾收集器、JIT,其他三个模块是一定要参与的。这三个模块也是研究Hotspot源码必先攻克的知识点。如果你没有自己尝试着写过,直接去读Hotspot源码,我相信会是丈二和尚摸不着头脑。写过一遍再回头去研究,不说轻松看懂吧,至少能更容易理解一些思想及为什么要这样做。

JVM运行Java程序的七步中,一直没看到我提内存模型对吧。因为内存模型对于JVM实在太重要,重要到根本不需要提,它无处不在:类解析器解析生成的klass对象要存储到JVM管理的内存中,我们知道是元空间;类中的属性与方法,解析后也会生成独立的对象存储到JVM管理的内存中,方法在元空间,属性不在;JVM运行Java程序需要创建虚拟机栈;JVM调用Java方法需要创建栈帧;字节码指令需要基于栈帧中的操作数栈及局部变量表运行……所以,最重要的前置知识是内存模型

关于内存模型,这篇文章我就不展开讲了。如果你觉得学得不够扎实,或者我上面讲得这些你好像不是很熟悉,可以看我之前讲过的JVM底层原理之内存模型。因为我的文章是全网发,有的平台不允许发链接及二维码,你可以关注我的公众号【硬核子牙】回复【Hotspot书】获取。

手写JVM框架输出hello world,深入理解内存模型就够了吗?当然!不够!还有字节码指令。我直接拿出字节码指令告诉你它做了什么什么你肯定没概念对吧,那我手动模拟程序的运行让你GET到学习字节码指令的感觉。



手动模拟程序运行

贴下上面的Java程序对应的字节码指令


java手写笔记 手写jvm_JVM_03


JVM在运行main方法的字节码指令前,会先构建运行环境。这个运行环境指:创建虚拟机栈、创建栈帧、根据常量池中提取的信息找到main方法对应的C++对象、从C++对象拿到操作数栈及局部变量表的尺寸来创建操作数栈及局部变量表……

java手写笔记 手写jvm_JVM_04


环境构建好后就可以运行程序了,那每个字节码指令做了什么呢:

1、getstatic:获取静态属性。这里是获取System.out对象

2、ldc:将字符串的内存地址压入栈顶。这里是将hello word对应的内存地址压入操作数栈的栈顶

3、invokevirtual:执行方法。这里是执行println方法

4、return:返回void。这里我们写JVM需要pop出main方法对应的栈帧,释放虚拟机栈,释放内存


实现细节

上面讲了JVM运行Java程序的七个步骤,这部分我就拿我自己手写的JVM代码带大家看下细节

一、实现步骤2、3、4


java手写笔记 手写jvm_编程语言_05


代码有注释,我就不展开讲了。这里面有个代码有小伙伴问过我,就是为什么要创建线程?的确,我们目前实现的JVM是单线程版本的,压根不需要引入线程,我为什么要这样做呢?一、与Hotspot源码尽量保持一致。因为我们手写JVM的目的之一是为了更好的研究Hotspot源码;二、保持向后兼容。如果我不通过线程管理虚拟机栈,我得通过全局变量来管理,那我后面想将单线程的JVM升级为多线程的,这块我要做大改,属于项目重构,那为何不在开发之初就做好这个扩展呢?二、实现步骤5


java手写笔记 手写jvm_编程语言_06


代码有注释,就不展开讲了三、实现步骤6


java手写笔记 手写jvm_java_07


我实现的是字节码解释器,运行效率不高,但是便于理解。JVM中目前在用的是模板解释器。什么?为什么不实现模板解释器?不是我不能教,是我没法教,模板解释器本质上是硬编码编织技术。以我对大家水平的了解,教这个属于劝退。但是我也不是完全放弃教这块了,但是可能要到手写JVM小班的五六期,等大家的基础补上来了。如果你不了解我说的,可以看我的JVM底层原理第十讲,我详细讲了模板解释器的底层实现原理。四、实现步骤7


java手写笔记 手写jvm_java_08


代码有注释,就不展开讲了



结语

没有人天赋异禀,这个世界其实很公平,它会残酷地惩罚那些不思进取不图改变的人,也会悄悄犒赏那些坚持努力奋斗的人。共勉。