java虚拟机初步简介
前言:
我因为自己学习java的东西越来越多,很多东西只得皮毛而不得窥其门道,伴随知识的增长,这种现象让我越来越痛苦,为不知道java对象在JVM内部如何存在而痛苦,为子类到底有没有继承父类的私有属性而痛苦,为当子类重写父类方法时,到底如何选择正确的方法并执行而痛苦,带着这些疑问,我们来揭秘JVM神秘的面纱。
1简介
作为一名资深的java开发者。那么你一定知道这一个人,一句话,江湖人称“java之父” --- 詹姆斯•高斯林,write once,run anywhere!这里尊称为“詹爷”,毕竟java给了我们这些从事java开发者生活的饭碗,詹爷希望开发一款编程语言,能够兼容所有的硬件平台和操作系统。
为了实现这一理想,那么我们需要实现两大目标
1,实现兼容性
2.开发者不需要关注底层平台的异构性,就能实现兼容。
2.为了实现上面两个目标,詹爷使用了中间语言(IL),当程序员编写一条指令,在linux平台上运行,自动编译成linux指令,在windows平台上运行,自动编译成windows指令,詹爷定义了字节码规范,字节码就是中间语言指令,同时詹爷开发了虚拟机,虚拟机负责将字节码转换成不同平台的API调用。因此,我们的目标得以达成,开发者不需要关注底层硬件和操作系统层面的细节,一切由虚拟机解决。
2.从中间语言到机器码
1.当我们使用java编写出的程序编译成字节码文件,但是我们的机器只能识别机器码,为了将字节码编译成对应的机器码,一种可行的方式是使用C程序,将字节码解释成为c程序。当执行字节码的程序时---JVM程序本身被编译后,字节码指令所对应的C程序一起编译成本地机器码,于是JVM在解释字节码指令时,自然就会执行对应的C程序所对应的本地机器码。第一代的JVM执行引擎就是这么做的,但是这么做有一个巨大缺陷---效率低下。
3.直接翻译成机器码
1.将中间语言翻译成机器码,办法很多,追根到底,我们还是利用了CPU执行代码的原理。要让CPU执行一段代码,只需将CS:IP段寄存器指向代码段入口即可。CS与IP是物理CPU内部的两个寄存器,CPU在取指时,完全依靠这两个寄存器。CS寄存器保存段地址,IP保存偏移地址。C语言提供了一种办法,可以将CS:IP直接指向某个入口地址,这种办法就定义函数指针,因此我们可以预先定义一串本地机器指令,然后直接通过C语言执行。请看示例1。
示例1:
通过C语言的函数指针达到间接修改CS:IP段寄存器的指向目的。函数指针可以指向一个char数组的首地址,char数组中保存一串数字,这些数字其实是X86平台上的一串机器指令,因此CPU可以直接将其当做指令来执行。看示例2。 有了这个功能,大家可以用它来实现各种动态功能,可以在运行期动态修改程序走向,可以实现一个高扩展的架构。正因为如此,使得java性能突飞猛进,在某种程度上,甚至超越C和C++的速度了。
示例2:
这样,我们只需要实现将中间语言,直接编译成机器语码,就可以直接运行,其效率比使用C语言来执行提升很高,为了提升性能,JVM提供了一种机制,能够将中间语言(字节码)直接编译成本地机器指令。事实上,JVM大牛们在JIT(即时编译),内存分配方面倾入了大量心血,能够对热点代码进行大幅度优化,优化后的指令比C,C++编译的指令更高。