JAVA虚拟机(JVM)二:JVM工作原理

一、前言

前一节,简单介绍了JAVA的体系结构,其中JVM尤为重要,它是JAVA的核心和基础。

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

显然,JVM是JAVA的重中之重,作为一个JAVA系的开发者,必须要对JVM有深刻的理解,才能写出高效合理的JAVA程序。

前提:本文讲的基本都是以Sun HotSpot虚拟机为基础的

二、JVM简述

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。

JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种利用软件方法实现的抽象的计算机基于下层的操作系统和硬件平台,可以在上面执行java的字节码程序。

它的组成结构如下:


jvm组成结构图-粗略

java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。

三、JVM的生命周期

首先分析两个概念:

  • JVM实例,对应了一个独立运行的java程序,它是进程级别。
  • JVM执行引擎实例, 则对应了属于用户运行程序的线程,它是线程级别的。

JVM的生命周期

1、JVM实例的诞生:当启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点。

2、JVM实例的运行: main()作为该程序初始线程的起点,任何其他线程均由该线程启动。
JVM内部有两种线程:守护线程非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程。

3、JVM实例的消亡:当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出。

JVM在它的生存周期中有一个明确的任务,那就是运行Java程序,因此当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。下面我们从JVM的体系结构和它的运行过程这两个方面来对它进行比较深入的研究。

四、JVM工作原理

JVM工作原理

1、JVM的系统结构

JVM的系统结构,也可是说是JVM的原理和工作流程:

1、类装载器(ClassLoader)子系统: 用来装载.class文件,装载具有适合名称的类或接口

加载
链接
初始化

2、运行时数据区

方法区

java栈
程序计数器
本地方法栈

3、执行引擎 :Execution Engine执行字节码,或者执行本地方法,负责执行包含在已装载的类或接口中的指令

4、本地接口: Native Interface负责调用本地接口。他的作用是调用不同语言的接口给JAVA用,他会在Native Method Stack中记录对应的本地方法,然后调用该方法时就通过Execution Engine加载对应的本地lib。原本多于用一些专业领域,如JAVA驱动,地图制作引擎等,现在关于这种本地方法接口的调用已经被类似于Socket通信,WebService等方式取代。

由于篇幅原因,后面会分节对各个部分进行详细讲解。

2、JVM的运行原理

Java 程序被javac工具编译为.class字节码文件之后,我们执行java命令,该class文件便被JVM的ClassLoader加载。JVM的初始化、运行到结束大概包括这么几步:

  • 调用操作系统API判断系统的CPU架构,根据对应CPU类型寻找位于JRE目录下的/lib/jvm.cfg文件;
  • 通过该配置文件找到对应的jvm.dll文件(如果我们参数中有-server或者-client, 则加载对应参数所指定的jvm.dll,启动指定类型的JVM);
  • 初始化jvm.dll并且挂接到JNIENV结构的实例上,
  • 通过JNIENV实例装载并且处理class文件了;
  • class文件是字节码文件,它按照JVM的规范,定义了变量,方法等的详细信息,JVM管理并且分配对应的内存来执行程序,同时管理垃圾回收;
  • 直到程序结束,一种情况是JVM的所有非守护线程停止,一种情况是程序调用System.exit(),JVM的生命周期也结束。

整个过程大概是:

1、将开发人员编写的Java代码(.java文件)编译成字节码(.class文件)

2、字节码(.class文件)装入内存

3、字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。

Java代码编译和执行的整个过程包含了以下三个重要的机制:

类编译

类编译机制

类加载

类加载机制

类执行

类执行机制

1、类编译

Java代码编译是由Java源码编译器来完成,也就是Java代码到JVM字节码(.class文件)的过程。

java代码到jvm字节码.png

Java 源码编译由以下三个过程组成:

分析和输入到符号表
注解处理
语义分析和生成class文件

类编译机制.png

最后生成的class文件由以下部分组成:

结构信息:包括class文件格式版本号及各部分的数量与大小的信息
元数据:对应于Java源码中声明与常量的信息。包含类/继承的超类/实现的接口的声明信息、域与方法声明信息和常量池
方法信息:对应Java源码中语句和表达式对应的信息。包含字节码、异常处理器表、求值栈与局部变量区大小、求值栈的类型记录、调试符号信息

2、类加载

加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。

详见 Android热更新一:JAVA的类加载机制

3 类执行

Java字节码的执行是由JVM执行引擎来完成
流程图如下所示:


Java字节码执行.png

JVM是基于堆栈的虚拟机。JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。

JVM执行class字节码,线程创建后,都会产生程序计数器(PC)和栈(Stack),程序计数器存放下一条要执行的指令在方法内的偏移量,栈中存放一个个栈帧,每个栈帧对应着每个方法的每次调用,而栈帧又是有局部变量区和操作数栈两部分组成,局部变量区用于存放方法中的局部变量和参数,操作数栈中用于存放方法执行过程中产生的中间结果。

五、结语

本文对JVM的工作原理进行了整体的分析,让大家有个轮廓性的了解,接下来会深入的讲解每一个部分。

本人能力有限,这里只局限于本人的认知,如有描述不当的地方,麻烦诸位指出。

推荐阅读更多精彩内容