Java不是最强大的语言,但JVM是最强大的虚拟机
JVM需要class文件作为原材料,将class文件编译解释成机器指令来执行
我们在IDE中编写好的一个类,都是.java结尾的文件,但在执行时都会被编译成.class文件,当一个Java文件开始被执行时,会经过:
.java文件 -> 经过Java编译器(前端编译) -> .class文件 -> JVM装载class文件并编译解释成机器指令执行
Java文件经过编译后产生的class文件:
JVM与语言无关,它只需要符合JVM规范的class文件,不仅仅是Java,如果某个语言也能编译成class文件,且符合JVM规范,那么也可以交给JVM来执行,即JVM是跨语言的平台:
如果某个项目中,并行处理采用Clojure编写,展示层采用JRuby编写,中间层则是Java,每个应用层采用不同的编程语言来完成,在JVM上使用多种语言混合编程是完全可行的,因为这些语言编译后的class文件都会运行在同一个JVM上
JVM是一个虚拟机(Vistrual Machine),虚拟机就是一个软件,用来执行一系列虚拟计算机指令,虚拟机大致可分为两类:
系统虚拟机 如VMware, Visual Box就是系统虚拟机,是对物理计算机的仿真 提供了一个可运行完整操作系统的软件平台 程序虚拟机 最典型的就是JVM,专门用来执行单个程序 JVM中执行的指令又称为字节码指令,即class文件的内容 JVM这个软件负责编译解释class文件的内容为CPU能看懂的机器指令并执行
JVM:一台执行class文件的虚拟计算机,拥有独立的运行机制,JVM平台上的各种语言都可以编译成class文件在JVM上执行,共享JVM的跨平台性,拥有优秀的垃圾回收器,可靠的即时编译器,自动内存管理…
JVM运行在操作系统之上,与硬件没有直接的交互,不同的操作系统上的JVM是有区别的,不同的硬件系统执行同一操作的机器语言是不同的,为此每种系统上都要有一款JVM,该系统上的JVM负责将class文件编译解释为该系统能辨识的机器指令
不同系统上需要不同的JVM:
Java程序所谓的write once,run anywhere指的是编写好的Java程序能够不经过修改,就能直接在同平台上的其它机器上运行,本质上是同平台上所有机器安装的JVM都是相同的,对同一个class文件的执行方式也是相同的
目前使用最广泛的JVM是HotSpot VM,它采用解释器和即时编译器并存的架构,随着JVM的不断优化和更新,目前Java程序的运行性能已与C/C++所差无几
有两种指令集架构,一种是基于栈的指令集架构,另一种是基于寄存器的指令集架构,而JVM采用的是基于栈的指令集架构
两种架构的特点:
基于栈的指令集架构: 1,设计和实现更简单,适用于资源受限的系统 2,避开了寄存器的分配问题,使用零地址指令方式分配 3,指令流中的指令大部分是零地址指令,执行过程依赖于栈 指令集更小,编译器更容易实现 4,不需要硬件支持,可移植性更好,更好实现跨平台 基于寄存器的指令集架构: 1,典型的x86二进制指令集,如传统PC 2,指令集完全依赖硬件,可移植性差 3,性能优秀,执行更高效 4,花费更少指令完成一项操作 5,基于寄存器架构的指令集往往是 一地址指令,二地址指令和三地址指令为主 而基于栈的指令集架构是零地址指令为主
执行2+3这样的操作,两种架构的指令如下:
做一个简单的测试来看看JVM的指令集架构:
上述的类只进行了简单的赋值操作,运行后可以在out目录里找到它经过编译后的字节码文件:
在IDEA中打开控制台,通过cd切换到该class文件所在目录,使用javap -v将这个字节码文件反编译:
这里着重看栈中的内容:
D:\JVM\About_JVM01\JVM_01\out\production\JVM_01\com\coisini\jvm\core>javap -v StackStuckTest.class // 省略了部分内容 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=4, args_size=1 0: iconst_2 // 定义常量2 1: istore_1 // 将常量2存储到栈中的下标为1的位置 2: iconst_3 // 定义常量3 3: istore_2 // 将常量3存储到栈中的下标为2的位置 4: iload_1 // 加载常量2 5: iload_2 // 加载常量3 6: iadd // 两个常量相加 7: istore_3 // 将结果存储到栈中的下标为3的位置 8: return LineNumberTable: line 12: 0 line 13: 2 line 14: 4 line 16: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 args [Ljava/lang/String; 2 7 1 i I 4 5 2 j I 8 1 3 k I } SourceFile: "StackStuckTest.java"
java文件中的三行代码实际上被翻译成了8行指令,通过栈来操作
总结:
由于JVM跨平台性的设计,Java指令都是根据栈来设计的,不同平台CPU架构不同,所以不能设计为基于寄存器的,优点是跨平台,指令集小,指令多,编译器容易实现,缺点是性能下降,实现同样功能需要更多的指令
JVM生命周期主要分为三个阶段:
1,JVM启动(进行类加载):
JVM的启动是通过引导类加载器(bootstrap class loader)
创建一个初始类(initial class)来完成的
这个类是由虚拟机的具体实现指定的
当想执行某个Java程序时,需要先启动JVM,进行类加载过程,即将执行main方法需要用到的类全部加载(main中出现的类及其父类等…)
2,JVM执行(启动新进程):
执行一个Java程序时,实际上是创建一个Java虚拟机实例
这个Java虚拟机实例就是一个负责执行Java程序的进程,用来将class文件翻译成机器指令并执行
可以在控制台中使用 jps来查看当前JVM中正在执行的进程:
3,JVM关闭(程序结束或异常):
退出的几种情况 1,JVM中的程序正常执行结束 2,程序在执行过程中遇到了异常或错误而终止 3,由于操作系统出现错误导致JVM终止 4,调用了System.exit()方法,直接退出 ...
Sun Classic VM-> Sun发布了Sun Classic VM 世界上的第一款商用JVM 只有解释器(逐行解释),没有JIT编译器(寻找热点代码并缓存) HotSpot VM-> 是JDK的默认虚拟机,服务器,桌面,移动端,嵌入式都有应用 HotSpot指的是热点代码探测技术,通过计数器找到最具有编译价值的代码 触发即时编译或栈上替换,通过编译器和解释器协同工作 JRockit-> 专注于服务器端应用,内部没有解释器实现,全部代码靠JIT编译后执行 是世界上最快的JVM,适合财务,军事指挥,电信网络 J9-> 市场定位与HotSpot接近,服务器端,桌面应用,嵌入式等多用途JVM 广泛用于IBM的各种Java产品 Azul VM-> 与特定硬件平台绑定,软硬配合使用的专有虚拟机,应用场景有限 在HotSpot基础上进行了大量改造,每个Azul VM实例 都可以管理至少数十个CPU和数百GB内存的硬件资源 TaobaoJVM-> 阿里发布,覆盖众多领域,为了解决高并发,高可用,分布式的复合问题 简称AJDK,是整个阿里Java体系的基石,但硬件严重依赖intel的CPU 损失了兼容性,提高了性能 Graal VM-> 在HotSpot上增强而成的跨语言全栈虚拟机 可以作为“任何语言”的运行平台使用,支持不同语言混用对方的API 工作原理是将这些语言的源或源码解析后的中间格式,通过解释器转换 为Graal VM能识别的文件,最有可能取代HotSpot VM