欢迎来到“Under The Hood”第一期。本期,我将给出JVM的基本结构和功能介绍。
什么是JVM?为什么要有它?
JVM(Java虚拟机)是一个运行已编译Java程序的抽象计算机。之所以说是”虚拟“的,是因为它基于“真正”的硬件平台和操作系统,一般以软件的形式实现。所有的Java程序都为JVM而编译。因此,在特定平台上运行已编译Java程序之前,该平台的JVM必须先要被实现。
JVM在Java的
跨平台特性中,起着中间人的角色。它在已编译Java程序与底层硬件平台和操作系统之间,提供一个抽象层。JVM对Java的可移植性非常关键,因为,已编译Java程序运行在JVM之上,并独立于底层JVM的具体实现。
那么,是什么导致JVM的短小精悍?当被实现成软件时,JMV很小巧。它被设计成这样,是为了让它能够适用于尽可能多的地方,比如机顶盒,手机和个人电脑。JVM很精悍,是因为它的野心。”
无处不在!“是它的战斗口号。它想要无处不在,并且Java程序”一次编写,到处运行“的程度说明了它的成功。
Java字节码
Java程序被编译成一种叫做字节码的东东。JVM执行Java字节码,所以字节码可以被认为是JVM的机器语言。Java编译器读取Java源文件,把它翻译成Java字节码并保存到类文件(.
class文件)中。编译器会为源码中的每一个类生成一个类文件。
对JVM来说,字节码流就是指令序列。每条指令包含一个单字节的操作码和零个或多个操作数。操作码告诉JVM要执行的操作。如果JVM需要除操作码之外更多的信息去执行一项操作,那么,需要的信息作为操作数,紧跟在操作码之后。
每个字节码都有一个助记符,它可被当作JVM的汇编语言。例如,有个指令会让JVM把0压到
堆栈中。该指令的助记符是iconst_0,字节码值是0×60。该指令没有操作数。另一个指令让程序的执行在
内存中无条件向前向后跳转。这个指令需要一个操作数,它是一个指明从当前内存地址开始的2字节无符号偏移量。通过把偏移量加到当前内存地址,JVM可以获得要跳转的目标内存地址。该指令的助记符是goto,它的字节码值是0xa7。
虚拟部分
JVM的“虚拟硬件”可以分为四个部分:寄存器组,栈区,垃圾收集堆和方法区。这些部分很抽象,就像由它们组成的虚拟机一样;但是它们必须在每个JVM的实现中,以某种形式存在。
JVM中地址的是32位(4字节)的,因此,JVM可以处理4GB(2的32次方)的内存。栈区,垃圾收集堆和方法区处在这4GB内存中的某个地方,至于它们的具体内存地址,这取决于每个特定JVM的实现者。
JVM中一个字(word)的长度是32位的。JVM中有少数几个原始数据类型:byte(8位),short(16位),int(32位),long(64位),float(32位),double(64位),char(16位)。除了无符号Unicode字符char之外,其他6种数字类型都是有符号的。这些类型可以方便的映射到Java
程序员可用的数据类型。另一个原始类型是对象句柄,它是一个指向堆中对象的32位地址。
由于包含字节码,方法区以字节边界对齐。栈和垃圾收集堆以字(32位)边界对齐。
寄存器:我少我自豪
JVM有1个程序计数器(counter)和3个管理栈的寄存器(register)。它只有很少的寄存器,是因为JVM字节码指令主要操作栈区。这种面向栈的设计,使得JVM指令集和JVM实现很小巧。
JVM使用程序计数器(也叫pc寄存器),跟踪当前执行指令的内存位置。另外3个寄存器(optop寄存器,frame寄存器和vars寄存器)指向当前执行方法栈帧上不同的部位。执行方法的栈帧持有特定方法调用的状态(本地变量,即时计算结果等)。
方法区和程序计数器
方法区是字节码呆的地方。程序计数器跟踪执行
线程。当前字节码指令执行后,程序计数器会包含下一条执行指令的地址:一条指令执行之后,JVM把程序计数器设置为紧跟上一条指令的指令地址,除非上一条指令具体指明一次跳转。
Java栈和相关寄存器
Java栈用来保存字节码指令的参数和执行结果,给方法传递参数和返回结果,保存每个方法调用的状态。方法调用的状态被称为调用栈帧。var寄存器,frame寄存器和optop寄存器指向当前栈帧的不同部位。
Java栈帧有3个区:本地变量,执行环境和操作数栈。本地变量区,包含当前方法调用中使用的所有本地变量。它由vars寄存器指向。执行环境区用来维护栈区本身的操作。它被frame寄存器指向。操作数区用来作为字码指令的工作区。正是在这里,存放着字节码指令的参数和其返回结果。操作数栈区的顶部被optop寄存器指向。
执行环境通常夹在本地变量和操作数栈中间。当前执行方法的操作数栈总是在栈区的最上面,所以optop寄存器总是指向整个Java栈的顶部。
垃圾收集堆
堆是Java对象生存的地方。任何时候,你用new
caozuofu.html" target="_blank">操作符分配的内存,都来自堆中。Java语言不允许你直接释放分配的内存。运行时环境会跟踪堆上每个对象的引用,自动释放那些不被引用的对象所占据的内存,这个过程被称为垃圾收集。
参考
- 关于内存对齐方式,请参考Data alignment: Straighten up and fly right。
本文译自:The lean, mean, virtual
machine
原创文章,转载请注明: 转载自LetsCoding.cn
本文地址: 短小精悍的虚拟机:JVM基本结构和功能介绍