jvm_overview

第三十三章 Java虚拟机概述(Java Virtual Machine Overview)

1 概述

Java虚拟机(JVM)是整个Java语言体系的基石。Java虚拟机的主要责任是为开发人员提供独立于硬件平台(Hardware Independent)和操作系统(Operating System Independent)的、安全的(Secure)运行环境。因为Java虚拟机拥有众多特性,我们首先从不同视角来解读Java虚拟机的重要性与在Java生态环境中的角色,以帮助读者全方位的了解Java虚拟机的功能特点。

1.1 Java虚拟机是一个抽象计算机器(Abstract Computing Machine)

Java虚拟机有标准化的指令集,在运行时可以操作内存中的数据。与日常所见的服务器或者笔记本类似,服务器上的指令是在CPU上运行的;在运行时,CPU可以读取和修改内存中的数据。而Java虚拟机建立的是一个虚拟的机器;所有的指令由Java虚拟机中的“运算器”运行,运行的数据存放在内存中。因为Java虚拟机的指令已标准化,经编译,Java虚拟机可以运行任何遵守标准化指令的程序。换句话说,Java虚拟机不仅可以运行Java程序,还可以运行Scala程序,Kotlin程序,Clojure程序,Lua程序等。这些编程语言的编译器可以将其源代码转换成JVM标准指令(俗称,Java二进制代码,Java ByteCode)。

图一 Java虚拟机与服务器的比较

图一 Java虚拟机与服务器的比较

1.2 Java虚拟机是一个统一的运行环境(Uniform Execution Environment)

Java语言的一个重要特性就是一次编译、到处运行。Java虚拟机为Java程序提供了一个统一的、独立于硬件和操作系统的运行环境。在Java程序中,无论程序将会运行于什么硬件/软件环境中,开发人员面对的都是同一运行环境,例如,Java语言的字符串都是由16位字符组成的。其背后的原理是Java虚拟机承担了适配各种不同环境的职责,这包括适配数据类型宽度的不同,操作系统提供接口的不同,各种硬件环境的不同(例如:适配服务器环境,移动设备环境等)。

图二 Java虚拟机提供统一的运行环境

图二 Java虚拟机提供统一的运行环境

1.3 Java虚拟机是一个动态的运行环境(Dynamic Execution Environment)

Java虚拟机提供了动态加载和卸载运行库的功能。在Java虚拟机初始化时,它会加载Java标准库和待运行的程序。在运行过程中,Java虚拟机还可以动态的加载额外的代码库,或者卸载不再需要的代码。因此,Java虚拟机是一个动态的运行环境。

2 Java程序的工作流程。

众所周知,Java语言是先编译,后解释执行的语言。每个Java源程序(.java文件)都需要先经过编译器翻译成Java二进制代码文件(.class文件),然后,再由Java虚拟机加载并运行.class文件。整个运行的流程如下图所示。

  1. Java源代码(.java)文件经Java编译器转换为Java二进制(.class)文件。.class文件的格式会在第三十六章详细介绍。
  2. 在Java虚拟机初始化时,类加载器(Class Loader)将.class文件加载至内存中。类加载的过程可分为三个步骤:加载、链接、和初始化。我们将在Java虚拟机初始化章节和类加载器章节详细介绍这个过程。
  3. 当一个.class文件加载完毕后,类加载器会为其创建一个Class对象,并且将代码放在方法区中。我们将在第三十七章详细介绍Java虚拟机内部的内存结构。
  4. 当Java虚拟机运行Java程序时,Java解释器(Java interpreter)会解释运行Java二进制代码。我们将从第三十九章开始详细介绍Java解释器的运行原理。
  5. 在程序运行过程中,当需要使用平台功能时(例如:申请内存或者创建一个线程),Java解释器会调用平台接口。
  6. 平台接口会根据当前运行的硬件和操作系统调用相应的平台接口。

图三 Java程序工作流程图

图三 Java程序工作流程图

3 Java虚拟机的功能和重要组成部分

除了执行Java二进制代码以外,Java虚拟机还有许多其他的重要功能。我们总结如下:

  1. Java虚拟机加载和释放.class文件。
  2. Java虚拟机解释执行Java二进制代码。
  3. Java虚拟机检查.class文件的版本兼容性。
  4. Java虚拟机与底层硬件和操作系统交互;通过调用底层接口以支撑Java代码的运行。例如:创建一个新对象时需要向操作系统申请内存。
  5. Java虚拟机执行垃圾回收,自动释放那些不被使用的对象。
  6. Java虚拟机优化代码。JIT(Just-in-Time)编译器会将常用的Java二进制代码翻译为机器代码,以加快Java程序的运行速度。
  7. Java虚拟机调试功能等。

因此,从上述功能可以看出,Java虚拟机有以下重要的组成部分。

  1. 类加载器(Bootstrap Class Loader)。
  2. 解释器(Interpreter)。
  3. 链接器(Linker)。
  4. 本地方法接口(Native Method Interface, JNI)和本地方法库(Native Method Library)。
  5. 垃圾回收器(Garbage Collecotr)。
  6. JIT编译器(JIT Compiler)。
  7. 调试模块(Debugging Module)。

4 其他

4.1 JVM实现

因为Java虚拟机的指令集已标准化,除了我们常用的OpenJDKOracle JDK里的Java虚拟机,各大厂商也开发了各自的实现。例如:Eclipse OpenJ9GraalVMAmazon Corretto等。

从实现所使用的语言来看,绝大多数Java虚拟机是用C/C++语言实现的;然而,GraalVM是使用Java语言实现的。小水滴相信在未来会出现更多语言的实现版本(例如:go语言rust语言)。

4.2 JVM与JRE的关系

JRE是Java运行环境(Java Runtime Environment),它包括了Java虚拟机,Java标准库和一些其他的功能(例如:调试功能)。所以,我们可以粗略的认为JRE=JVM+Java标准库。

4.3 JIT编译器

JIT(Just-in-Time)是一种较新的技术,其原理是:因为Java语言是解释执行的;从运行速度上看,解释执行的速度慢于直接运行相对应的机器代码。因此,JIT编译技术能够将Java二进制代码转换为等价的机器代码,用于提升Java程序的运行速度。JIT编译器是集成在Java虚拟机里的。Java虚拟机会将经常运行的代码转换成机器代码。这个转换过程是由Java虚拟机控制的,完全对开发人员或者Java程序透明。但是,JIT技术尚不成熟,编译出的机器代码也存在兼容性问题,而且,各个JVM采用了不同的实现方法。因此,本系列文章目前并不打算详细介绍其中的细节。

4.4 JVM调式功能

Java虚拟机还可以运行于调式模式中,以便于开发人员定位和调式应用程序。Java语言为调式功能指定了统一的框架和调式接口,该框架称为Java Platform Debugger Architecture(JPDA)。因为Java环境的调试框架又是一块较大的内容,我们并不打算在Java虚拟机章节中介绍。有兴趣的读者可参考JPDA文档

5 本系列文章的安排

我们会在后续章节中重点介绍Java虚拟机的几个重要的功能部件,以覆盖Java虚拟机的重要功能。后续章节安排如下。

 

上一章
下一章

注册用户登陆后可留言

Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.