虚拟机

所谓虚拟机(Virtual Machine), 就是一台虚拟的计算机。它是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机程序虚拟机。大名鼎鼎的Visual Box, VMware就属于系统虚拟机,它们完全是对物理计算机的仿真,提供了一个可运行完整操作系统的软件平台。

程序虚拟机的典型代表就是Java虚拟机,它专门为执行单个计算机程序而设计,在Java虚拟机中执行的指令我们称为Java字节码指令。

无论是系统虚拟机还是程序虚拟机,在上面运行的软件都被限制于虚拟机提供的资源中。

Java虛拟机

  1. Java虚拟机是一台执行Java字节码的虚拟计算机,它拥有独立的运行机制,其运行的Java字节码也未必由Java语言编译而成。
  2. JVM平台的各种语言可以共享Java虚拟机带来的跨平台性、优秀的垃圾回器,以及可靠的即时编译器。

Java技术的核心就是Java虚拟机(JVM, Java Virtual Machine) ,因为所有的Java程序都运行在Java虚拟机内部。它是通过模拟一个计算机所具有的计算功能。

一个真实的计算机如何才能具备计算的功能?

  1. 指令集:这个计算机所能识别的机器语言的命令集合。
  2. 计算单元:即能够识别并且控制指令执行的功能模块。
  3. 寻址方式:地址的位数、最小地址和最大地址范围,以及地址的运行规则。
  4. 寄存器定义:包括操作数寄存器、变址寄存器、控制寄存器等的定义、数量和使用方式。
  5. 存储单元:能够存储操作数和保存操作结构的单元,如内核级缓存、内存和磁盘等。

在上面这几个部分中与我们所说的代码执行最密切的还是指令集部分,下面详细说明一下在计算机中指令集是如何定义的。

什么是指令集?有何作用?

所谓指令集就是在CPU中用来计算和控制计算机系统的一套指令的集合,每一种新型的CPU在设计时都规定了一系列与其他硬件电路相配合的指令系统。而指令集的先进与否也关系到CPU的性能发挥,它是体现CPU性能的一个重要标志。
 

在当前计算机中有哪些指令集?

从主流的体系结构上分为精简指令集和复杂指令集当前我们普遍使用的桌面操作系统中基本上使用的都是复杂指令集,如x86架构的CPU都使用复杂指令集。除了这两种指令集之外Intel和AMD公司还在它们的基础上开发出了很多扩展指令集,如MMX (Multi Media eXtension,多媒体扩展指令)使得在处理多媒体数据时性能更强,还有AMD公司为提高3D处理性能开发的3DNow!指令集等。

指令集与汇编语言有什么关系?

指令集是可以直接被机器识别的机器码,也就是它必须以二进制格式存在于计算机中。而汇编语言是能够被人识别的指令,汇编语言在顺序和逻辑上是与机器指令一一对应的。换句话说,汇编语言是为了让人能够更容易地记住机器指令而使用的助记符。每一条汇编指令都可以直接翻译成一个机器指令,如MOVAX,1234H这条汇编语言对应的机器指令码为B83412。当然也不是所有的汇编语言都有对应的机器指令,如nop指令。

指令集与CPU架构有何联系? 如Intel 与AMD的CPU的指令集是否兼容?也就是CPU的架构是否会影响指令集?

答案都是肯定的。学过汇编语言的人都知道在汇编语言中都是对寄存器和段的直接操作的命令,这些寄存器和段等芯片都是架构的一部分, 所以不同的芯片架构设计一定会对应到不同的机器指令集合。但是现在不同的芯片厂商往往都会采用兼容的方式来兼容其他不同架构的指令集。如AMD会兼容32位Intel的x86系统架构的CPU,而当AMD开发出了支持64位指令的x86-64架构时,
Intel 又迫于压力不得不兼容这种架构而起了另外一个名字EM64T。 这种压力来自什么地方? 当然是垄断了操作系统的微软,由于现在操作系统是管理计算机的真正入口,几乎所有的程序都要通过操作系统来调用,所以如果操作系统不支持某种芯片的指令集,用户的程序是不可能执行的。这种情况也存在于我们国家自己设计的龙芯CPU,龙芯CPU不得不使用基于MIPS架构的指令集(是RISC指令集),因为目前有直接支持MIPS架构的操作系统(Linux 操作系统,目前Windows不支持)。如果没有操作系统和应用软件,再好的CPU也没有使用价值。当然在些很少用到的大型机方面不存在这个问题。

JVM和实体机到底有何不同呢?大体有如下几点。

  1. 一个抽象规范,这个规范就约束了JVM到底是什么,它有哪些组成部分,以及每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放在哪里。
  2. 一个具体的实现,所谓具体的实现就是不同的厂商按照这个抽象的规范用软件或者软件和硬件结合的方式在相同或者不同的平台上的具体的实现。
  3. 一个运行中的实例,当用其运行一个Java程序时,它就是个运行中的实例, 每个运行中的Java程序都是一个JVM实例。

JVM和实体机一样也必须有套合适的指令集, 这个指令集能够被JVM解析执行。这个指令集我们称之为JVM字节码指令集,符合class文件规范的字节码都可以被JVM执行。Java虚拟机就是二进制字节码的运行环境,负责装载字节码到其内部,解释/编译为对应平台上的机器指令执行

Java虚拟机的整体结构

java虚拟机是干嘛的 java虚拟机是jvm吗_指令集

  1. 类加载器:在JVM启动时或者在类运行时将需要的class加载到JVM中
  2. 执行引擎:执行引擎的任务是负责执行class文件中包含的字节码指令,相当于实际机器上的CPU。
  3. 内存区:将内存划分成若干个区域以模拟实际机器上的存储、记录和调度功能模块,如实际机器上的各种功能的寄存器或者PC指针的记录器等。
  4. 本地方法调用:调用C或C++实现的本地方法的代码返回结果。

Java虚拟机特点

一次编译,到处运行。  自动内存管理。   自动垃圾回收功能。

JVM的架构模型:

栈的指令集架构,另外一种指令集架构则是基于寄存器的指令集架构。

JVM执行字节码指令是基于栈的架构,也就是所有的操作数必须先入栈,然后根据指令中的操作码选择从栈顶弹出若干个元素进行计算后再将结果压入栈中。在JVM中操作数可以存放在每一个栈帧中的一个本地变量表中,即在每个方法调用时就会给这个方法分配一个本地变量表,这个本地变量表在编译时就已经确定,所以操作数入栈可以直接是常量入栈或者从本地变量表中取个变量压入栈中。这和一般的基于寄存器的操作有所不同,一个操作需要频繁地入栈和出栈,如进行一个加法运算, 如果两个操作数都在本地变量中,那么一个加法操作就要有5次栈操作,分别是将两个操作数从本地变量入栈(2次入栈操作),再将两个操作数出栈用于加法运算(2次出栈),再将加法结果压入栈顶(1次入栈)。如果是基于寄存器的话,一般只需要将两个操作 数存入寄存器进行加法运算后再将结果存入其中一个寄存器即可,不需要这么多的数据移动的操作。这也导致了基于栈的架构设计需要更多的指令。

那么为什么JVM还要基于栈来设计呢?

一个是JVM要设计成与平台无关的,而平台无关性就是要保证在没有或者有很少的寄存器的机器上也要同样能正确地执行Java代码。例如,在80x86的机器上寄存器就是没有规律的,很难针对某一款机器 设计通用的基于寄存器的指令,所以基于寄存器的架构很难做到通用。在手机操作系统方面,Google 的Android平台上的Dalvik VM就是基于特定芯片(ARM)设计的基于寄存器的架构,这样在特定芯片上实现基于寄存器的架构可能更多考虑性能,但是也牺牲了跨平台的移植性。

还有一个理由是为了指令的紧凑性,因为Java的字节码可能在网络上传输,所以class文件的大小也是设计JVM字节码指令的一个重要因素,如在class文件中字节码除了处理两个表跳转的指令外,其他都是字节对齐的,操作码可以只占一个字节大小, 这都是为了尽量让编译后的class文件更加紧凑。为了提高字节码在网络上的传输效率,Sun设计了一个Jar包的压缩工具Pack200,它可以将多个class文件中的重复的常量池的信息进行合并,如一般在每个clsss文件中都含有“Ljava/lang/String;",那么多个class文件中的常量就可以共用,从而起到减少数据量的作用。

基于栈式架构的特点

  1. 设计和实现更简单,适用于资源受限的系统;
  2. 避开了寄存器的分配难题:  使用零地址指令方式分配。(只需要关心栈顶,入栈出栈)
  3. 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。指令集更小,编译器容易实现。
  4. 不需要硬件支持,可移植性更好,更好实现跨平台。

基于寄存器架构的特点

  1. 典型的应用是x86的二进制指令集:比如传统的PC以及Android的Davlik虛拟机。
  2. 指令集架构则完全依赖硬件,可移植性差
  3. 性能优秀和执行更高效;
  4. 花费更少的指令去完成一项操作。
  5. 在大部分情况下,基于寄存器架构的指令集往往都以一地址指令、二地址指令。和三地址指令为主,而基于栈式架构的指令集却是以零地址指令为主。

由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。优点是跨平台, 指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。

JVM的生命周期

一、虚拟机的启动

Java虚拟机的启动是通过引导类加载器(bootstrap class loader) 创建一个初始类(initial class) 来完成的,这个类是由虚拟机的具体实现指定的。

二、虚拟机的执行

一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序。程序开始执行时他才运行,程序结束时他就停止。执行一个所谓的Java程序的时候,真真正正在执行的是一个叫做Java虛拟机的进程。

三、虚拟机的退出(有如下的几种情况)

  1. 程序正常执行结束
  2. 程序在执行过程中遇到了异常或错误而异常终止
  3. 由于操作系统出现错误而导致Java虚拟机进程终止
  4. 某线程调用Runtime 类或System类的exit方法,或Runtime 类的halt方法,并且Java安全管理器也允许这次exit或halt操作。除此之外,JNI ( Java Native Interface) 规范描述了用JNI Invocation API 来加载或卸载Java虚拟机时,Java 虚拟机的退出情况。

Java代码的执行流程

java虚拟机是干嘛的 java虚拟机是jvm吗_Java_02