一、JVM与Java体系结构
1、汇编语言、机器语言、高级语言关系
2、Java 的特性
跨平台性:
- 随着Java7的正式发布,Java虚拟机的设计者们通过JSR-292规范基本实现在Java虚拟机平台上运行非Java语言编写的程序。
- Java虚拟机根本不关心运行在其内部的程序到底是使用何种编程语言编写的,它只关心“字节码”文件。
- 每个语言都需要转换成字节码文件,最后转换的字节码文件都能通过Java虚拟机进行运行和处理
3、Java 代码执行过程详图
JAVA文件–>字节码文件–>JAVA虚拟机
4、虚拟机
系统虚拟机
- VMware:完全对物理计算机的仿真
程序虚拟机
- 专门执行单个计算机程序,JVM:执行Java字节码指令
- 字节码包含:JVM指令集、符号集、辅助信息
Java虚拟机就是二进制字节码的运行环境,负责装载字节码到其内部,解释/编译为对应平台上的机器指令执行。每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放在哪里。
- 跨平台性,一次编译,到处运行
- 自动垃圾回收功能
- 即时编译器JIT
- 自动内存管理
5、JVM 的架构模型
5.1、指令
指令分为地址和操作数
- 零地址只有操作数
- 一地址,一个操作数
- 二地址,一个操作数
5.2、基于栈式(虚拟机栈)
优点:
- 设计和实现简单,适用于资源受限的系统
- 避开了寄存器的分配难题:使用零地址指令方式分配,操作栈顶元素,不需要地址
- 指令流中大部分都是零地址指令,执行过程依赖操作栈,指令集更小,编译器容易实现,8位字节码,所以说指令集更小,但是完成一项操作花费的指令相对多
- 不需要硬件支持,可移植性更好,更好实现跨平台
缺点:
- 性能下降,实现同样的功能需要更多的指令,毕竟还要入栈出栈等操作
5.3、基于寄存器式
优点:
- 性能优秀,执行更高效
- 花费更少的指令去完成一项操作
缺点:
- 不同平台CPU架构不同,指令集架构完全依赖硬件,可移植性差,典型应用是X86的二进制指令集,比如传统的PC以及安卓的Davlik虚拟机
- 16位字节码,大部分情况下,指令集往往以一地址指令,二地址指令和三地址指令为主。
5.4、Java 反编译指令
javap 查看字节码:
- -c对代码进行反汇编
- -v 输出附加信息
- -l 输出行号和本地变量表
- -p 显示所有类和成员
测试代码:
public class StackStruTest {
public static void main(String[] args) {
int i = 2;
int j = 3;
int k = i + j;
}
}
编译结果:
6、JVM 的生命周期
6.1、虚拟机的启动
Java 虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。
6.2、虚拟机的执行
- 一个运行中的 Java虚拟机有着一个清晰的任务:执行Java程序。
- 程序开始执行时他才运行,程序结束时他就停止。
- 执行一个所谓的 Java 程序的时候,真真正正在执行的是一个叫做 Java 虚拟机的进程。
6.3、虚拟机的退出
-
程序正常执行结束
-
执行过程遇到异常或错误而异常终止
-
操作系统错误导致 Java 虚拟机进程终止
-
Runtime类或System类的exit方法、runtime类的halt方法,并且Java安全管理器允许这次exit或halt操作
-
halt停止、停下、阻止
-
exit方法源码:static native void halt0(int status)
-
JNI (Java Native Interface)规范描述了用JNI Invocation API来加载或卸载Java虚拟机时,Java虚拟机退出的情况
7、Java 虚拟机整体架构图
JVM 的主要组成部分及其作用
- 类加载子系统:加载字节码文件到运行数据区的方法区
- 执行引擎:执行字节码文件中的指令
- 本地方法接口:java调用其他语言的接口,与本地资源交互
- 运行时数据区:JVM的内存
执行流程
首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。
Java程序运行机制
- java代码–编译器–>字节码文件–类加载器–>方法区
- 堆:java.lang.Class对象–>封装方法区内数据结构