一、Java及JVM简介
1.1 如何看待框架
大部分Java开发人员,除了会在项目中使用到与Java平台相关的各种高精尖技术框架,对于Java技术的核心——Java虚拟机了解甚少。
一些有一定工作经验的开发人员,打心眼里觉得SSM、微服务等上层技术才是重点,基础技术并不重要,这其实是一种本末倒置的病态。
计算机系统体系对我们来说越来越远,在不了解底层实现方式的前提下,通过高级语言很容易编写程序代码,但事实上计算机并不认识高级语言。
1.2 为什么要学习JVM
- 面试的需要
- 中高级程序员必备技能,项目管理、调优的需要
- 追求极客的精神,垃圾回收算法、JIT(Just In Time)、底层原理
垃圾收集机制为我们打理了很多繁琐的工作,大大提高了并发的效率。但是垃圾收集也不是万能的,懂得JVM内部的内存结构、工作机制,是设计拓展性应用和诊断运行时问题的基础,也是Java工程师进阶 的必备能力。
1.3 Java生态圈
Java是目前应用最为广泛的软件开发平台之一。随着Java及Java社区的不断壮大,Java早已不是一门简单的计算机语言,而成为了一个平台、一种文化、一个社区。
- 作为一个平台,JVM扮演着举足轻重的作用,Groovy、Scala、JRuby、Kotlin都是基于JVM的。
- 作为一种文化,Java几乎成了开源的代名词,不仅有Tomcat、Mybatis、Spring等Java优秀框架,连JDK和JVM自身都有开源实现,如OpenJDK、Harmony。
- 作为一个社区,Java拥有全世界UI多的技术拥护者和开源社区支持。
1.4 JVM:跨语言的平台
write once, run anywhere. 一次编写,到处运行。
compile once, error everywhere. 一次编译,到处报错。
Java不是最强大的语言,但JVM是最强大的虚拟机,JVM是一个比Java更成功的作品。
随着Java7的发布,JSR-292规范实现了在JVM上运行非Java语言编写的程序。
Java虚拟机不关心运行在内部的程序到底是何种语言编写的,它只关心字节码文件,只要其他编程语言的编译结果满足并包含Java虚拟机的内部指令集、符号表以及其他辅助信息,就是一个有效的字节码文件,JVM就能识别并装载运行。
Java平台上的多语言混合编程正成为主流,各种语言间的交互不存在任何困难,就像使用自己语言的原生API一样方便,因为他们都运行在一个虚拟机之上。
二、Java发展的重大事件
在JDK11之前,Oracle JDK中还会存在一些Open JDK没有的,闭源的功能,但是在JDK11中,OpenJDK和OracleJDK代码实质上已经完全一致,只是协议不同。
三、虚拟机与Java虚拟机
3.1 什么是虚拟机
所谓虚拟机,就是一台虚拟的计算机,是一个软件,用来执行一系列虚拟计算机指令。
大体上分为系统虚拟机(Visual Box/VMware)和程序虚拟机(JVM),在虚拟机上运行的软件都被限制余虚拟机提供的资源。
分类
- 系统虚拟机完全是对物理计算机的仿真,提供了一个可运行操作系统的软件平台。
- 程序虚拟机专为执行单个计算机程序而设计,在JVM中执行的指令我们称为Java字节码指令,Java字节码未必由Java语言编译。
3.2 Java虚拟机
Java的核心技术就是JVM,因为所有的Java程序都运行在JVM上。
JVM平台的各种语言可以共享JVM带来的跨平台性、优秀的垃圾回收机器以及可靠的及时编译器。
作用
Java虚拟机就是二进制字节码的运行环境,负责装在字节码到其内部,解释/编译为对应平台上的机器指令执行。
每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放哪里。
特点
- 一次编译,到处运行。
- 自动内存管理。
- 自动垃圾回收功能。
四、JVM的整体结构
4.1 JVM的位置
4.2 JVM的整体结构
多线程共享方法区和堆,每个线程单独维护一份Java栈、本地方法栈、程序计数器。
详细版
五、Java代码执行流程
JIT编译器会对热点代码进行二次编译,直接编译成机器指令并缓存。
六、JVM的架构模型
Java编译器输入的指令流基本上是一种基于栈的指令集架构,另一种指令集架构是基于寄存器的指令架构。
6.1 基于栈式架构的特点
- 设计和实现更简单,适用于资源受限的系统。
- 避开了寄存器的分配难题,直接在栈顶操作,使用零地址指令方式进行分配。
- 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。指令集更小,编译器更容易实现。
- 不需要硬件支持,可移植性更好,更好实现跨平台。
6.2 基于寄存器架构的特点
- 指令集架构完全依赖硬件,可移植性差。
- 直接用cpu在高速缓存区高效执行,性能优秀。
- 花费更少的指令去完成一项操作。
- 指令集一般以一地址指令、二地址指令、三地址指令为主。
- 典型的应用是X86的二进制指令集,比如PC和Android和Davlik虚拟机。
6.3 class文件反编译
StackStrTest.java
public class StackStrTest {
public StackStrTest() {
}
public static void main(String[] args) {
int i=2;
int j=3;
int k = i+j;
}
}
在StackStrTest.class目录下执行反编译命令
javap -v StackStrTest.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
1: istore_1
2: iconst_3
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: return
6.4 总结
由于跨平台的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。
栈架构的优点是跨平台,指令集小,编译器容易实现。
缺点是性能下降,实现同样功能需要更多的指令。
七、JVM的生命周期
7.1 虚拟机启动
JVM的启动时通过引导类加载器(bootstarp class loader)创建一个初始类(initial class)来完成的,这个类是有虚拟机的具体实现指定的。
7.2 虚拟机执行
一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序。
程序开始执行时JVM就运行,程序结束时JVM就停止。
执行一个所谓的Java程序的时候,真真正正在执行的是一个叫做Java虚拟机的进程。
public class StackStrTest {
public static void main(String[] args) {
int i=2;
int j=3;
int k = i+j;
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("down!");
}
}
在命令行执行Jps,查看当前运行的Java进程
13908 Launcher
32324
41444 Jps
34280 StackStrTest
32236 KotlinCompileDaemon
7.3 虚拟机退出
- 正常执行结束。
- 程序在执行过程中遇到了异常或错误而异常终止。
- 由于操作系统出现而Java虚拟机进程终止。
- 某线程调用Runtime类或System类的exit/halt方法,并且Java安全管理器也允许这次操作。
八、JVM的发展历程
历史JVM
三大主流JVM
两款专用JVM
国内JVM
安卓虚拟机
展望
Q.E.D.
Comments | 0 条评论