短小精悍的虚拟机:JVM基本结构和功能介绍

[i]欢迎来到“[url=http://letscoding.cn/tag/under-the-hood/]Under The Hood[/url]”第一期。本期,我将给出JVM的基本结构和功能介绍。[/i]

[i][b]什么是JVM?为什么要有它?[/b][/i]

JVM(Java虚拟机)是一个运行已编译Java程序的抽象计算机。之所以说是”虚拟“的,是因为它基于“真正”的硬件平台和操作系统,一般以软件的形式实现。所有的Java程序都为JVM而编译。因此,在特定平台上运行已编译Java程序之前,该平台的JVM必须先要被实现。

JVM在Java的跨平台特性中,起着中间人的角色。它在已编译Java程序与底层硬件平台和操作系统之间,提供一个抽象层。JVM对Java的可移植性非常关键,因为,已编译Java程序运行在JVM之上,并独立于底层JVM的具体实现。

那么,是什么导致JVM的短小精悍?当被实现成软件时,JMV很小巧。它被设计成这样,是为了让它能够适用于尽可能多的地方,比如机顶盒,手机和个人电脑。JVM很精悍,是因为它的野心。”无处不在!“是它的战斗口号。它想要无处不在,并且Java程序”一次编写,到处运行“的程度说明了它的成功。

[i][b]Java字节码[/b][/i]

Java程序被编译成一种叫做字节码的东东。JVM执行Java字节码,所以字节码可以被认为是JVM的机器语言。Java编译器读取Java源文件,把它翻译成Java字节码并保存到类文件(.class文件)中。编译器会为源码中的每一个类生成一个类文件。

对JVM来说,字节码流就是指令序列。每条指令包含一个单字节的操作码和零个或多个操作数。操作码告诉JVM要执行的操作。如果JVM需要除操作码之外更多的信息去执行一项操作,那么,需要的信息作为操作数,紧跟在操作码之后。

每个字节码都有一个助记符,它可被当作JVM的汇编语言。例如,有个指令会让JVM把0压到堆栈中。该指令的助记符是iconst_0,字节码值是0×60。该指令没有操作数。另一个指令让程序的执行在内存中无条件向前向后跳转。这个指令需要一个操作数,它是一个指明从当前内存地址开始的2字节无符号偏移量。通过把偏移量加到当前内存地址,JVM可以获得要跳转的目标内存地址。该指令的助记符是goto,它的字节码值是0xa7。

[i][b]虚拟部分[/b][/i]

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位)边界对齐。

[b][i]寄存器:我少我自豪[/i][/b]

JVM有1个程序计数器(counter)和3个管理栈的寄存器(register)。它只有很少的寄存器,是因为JVM字节码指令主要操作栈区。这种面向栈的设计,使得JVM指令集和JVM实现很小巧。

JVM使用程序计数器(也叫pc寄存器),跟踪当前执行指令的内存位置。另外3个寄存器(optop寄存器,frame寄存器和vars寄存器)指向当前执行方法栈帧上不同的部位。执行方法的栈帧持有特定方法调用的状态(本地变量,即时计算结果等)。

[i][b]方法区和程序计数器[/b][/i]

方法区是字节码呆的地方。程序计数器跟踪执行线程。当前字节码指令执行后,程序计数器会包含下一条执行指令的地址:一条指令执行之后,JVM把程序计数器设置为紧跟上一条指令的指令地址,除非上一条指令具体指明一次跳转。

[i][b]Java栈和相关寄存器[/b][/i]

Java栈用来保存字节码指令的参数和执行结果,给方法传递参数和返回结果,保存每个方法调用的状态。方法调用的状态被称为调用栈帧。var寄存器,frame寄存器和optop寄存器指向当前栈帧的不同部位。

Java栈帧有3个区:本地变量,执行环境和操作数栈。本地变量区,包含当前方法调用中使用的所有本地变量。它由vars寄存器指向。执行环境区用来维护栈区本身的操作。它被frame寄存器指向。操作数区用来作为字码指令的工作区。正是在这里,存放着字节码指令的参数和其返回结果。操作数栈区的顶部被optop寄存器指向。

执行环境通常夹在本地变量和操作数栈中间。当前执行方法的操作数栈总是在栈区的最上面,所以optop寄存器总是指向整个Java栈的顶部。

[i][b]垃圾收集堆[/b][/i]

堆是Java对象生存的地方。任何时候,你用new操作符分配的内存,都来自堆中。Java语言不允许你直接释放分配的内存。运行时环境会跟踪堆上每个对象的引用,自动释放那些不被引用的对象所占据的内存,这个过程被称为垃圾收集。

[i][b]参考[/b][/i]

[list]
[*]关于内存对齐方式,请参考[url=https://www.ibm.com/developerworks/library/pa-dalign/]Data alignment: Straighten up and fly right[/url]。
[/list]
本文译自:[url=http://www.javaworld.com/article/2077184/core-java/the-lean--mean--virtual-machine.html]The lean, mean, virtual machine[/url]

[b]原创文章,转载请注明: 转载自[url=http://letscoding.cn/]LetsCoding.cn[/url]
本文地址: [url=http://letscoding.cn/%E7%9F%AD%E5%B0%8F%E7%B2%BE%E6%82%8D%E7%9A%84%E8%99%9A%E6%8B%9F%E6%9C%BA%EF%BC%9Ajvm%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84%E5%92%8C%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D/]短小精悍的虚拟机:JVM基本结构和功能介绍[/url][/b]

你可能感兴趣的:(编程实践)