JVM架构简介
我们Java程序员都知道,Java源代码经过编译后生成.class
字节码文件,而字节码最终会由JVM(Java虚拟机)加载运行。JVM的存在屏蔽了底层硬件和操作系统的细节,能够让我们的程序面向统一的执行架构编程,达到Java所宣称的“Write once, run anywhere”的目的,因此Java程序具有极好的跨平台性。
JVM是一种软件抽象的“计算机”,其内部包含程序模拟的处理器、堆栈、寄存器、指令集等,因此JVM属于一种应用层面的程序虚拟机。实际上,除了Java语言,JVM生态上还产生了许多其他语言,如我们经常听说的Clojure、Scala、Groovy、Kotlin等,这些语言也都能编译为JVM可识别的字节码,并由JVM执行。JVM只是一种规范,其实现有很多种,包括HotSpot、JRockit(已与HotSpot合并)、OpenJ9等,不过我们最常用的还是Oracle的HotSpot虚拟机,目前OracleJDK和OpenJDK均集成了HotSpot。经过二十多年的迭代,JVM上诞生了庞大的生态系统,HotSpot本身也是当下最先进的虚拟执行架构之一。
随着时代的发展,JVM也在进行不断的迭代和优化,本系列笔记和后面介绍的内容也都是以Java8前后的HotSpot虚拟机为例,对JVM内部的架构进行简单介绍,了解这些知识能够让我们在使用Java等语言编程时更加得心应手。
什么是Java虚拟机
虚拟机(Virtual Machine)就是一台软件实现的虚拟计算机,可以大致分为系统虚拟机和程序虚拟机:
- 系统虚拟机:例如QEMU,它能够完全模拟x86或是arm等物理计算机架构,我们可以在其上部署操作系统
- 程序虚拟机:例如Java的HotSpot,它实现了一个跨平台的统一执行架构,使得在其上能够实现内存安全、垃圾回收等高级特性,以及我们程序的跨平台性
Java虚拟机就属于程序虚拟机,我们的Java源代码经过编译后生成JVM字节码,其中包含类似于汇编指令的JVM指令,Java虚拟机负责加载字节码,并解释执行或是即时编译(JIT)为对应平台上的机器指令执行。
Java虚拟机有3个特点:
- 一次编译,到处运行
- 自动、安全的内存管理
- 垃圾回收机制
JVM架构简介
HotSpot是目前应用最广泛的Java虚拟机,其结构主要分为类装载子系统、运行时数据区和执行引擎,HotSpot的执行引擎采用了解释执行和即时编译(JIT)并存的架构,具有较好的执行性能。如下图所示,为Java8的HotSpot虚拟机架构。
JVM的内存布局
从上面图可以看出,JVM的内存布局分为如下几部分:
- 程序计数器,虚拟机栈,本地栈
- 堆,元空间,代码缓存
我们知道JVM是支持多线程的,JVM会将每一个线程和操作系统的线程一对一映射。上面我们把内存区分为了两种,前者是线程独有的,后者是线程共享的。
有关JVM架构的每一部分,我们会在后文详细介绍。
基于操作数栈的指令集架构
除此之外我们还应该知道,JVM规范的指令采用了一种基于操作数栈的指令集架构,此外另一种是基于寄存器的指令集架构(如Android的Dalvik虚拟机)。这两种架构的区别如下:
基于栈的指令集架构:1)设计和实现更简单,能够避开寄存器的分配难题,但执行效率相对低一些 2)采用更短的零地址指令,编译器容易实现,但完成一个操作需要的指令数更多 3)不需要特定硬件支持,可移植性好。
基于寄存器的指令集架构:1)充分利用硬件特性,执行效率更高,但可移植性差 2)指令更长,但完成一个操作需要的指令更少。
JVM的生命周期
虚拟机的启动:JVM的启动是通过引导类加载器(BootStrap Class Loader)创建一个初始类来完成的,这个类是由虚拟机的具体实现指定的。
虚拟机的执行:一个运行中的JVM有着一个清晰的任务:执行Java程序。程序开始执行时它才运行,程序结束时它就停止。执行一个Java程序时,真真正正在执行的是一个叫做Java虚拟机的进程。
虚拟机的退出:虚拟机退出有如下几种情况:1)程序正常结束 2)程序在执行过程中遇到了异常或错误而终止 3)由于操作系统出现错误导致Java虚拟机进程终止 4)某程序调用了Runtime类或System类的exit()
方法,或Runtime类的halt()
方法,并且Java安全管理器也允许了这次操作。