提及Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成: Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口 (Java API) 。它们的关系以下图所示: java
运行期环境表明着Java平台,开发人员编写Java代码(.java文件),而后将之编译成字节码(.class文件)。最后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。从上图也能够看出Java平台由Java虚拟机和 Java应用程序接口搭建,Java语言则是进入这个平台的通道,用Java语言编写并编译的程序能够运行在这个平台上。这个平台的结构以下图所示: 程序员
在Java平台的结构中, 能够看出,Java虚拟机(JVM) 处在核心的位置,是程序与底层操做系统和硬件无关的关键。它的下方是移植接口,移植接口由两部分组成:适配器和Java操做系统, 其中依赖于平台的部分称为适配器;JVM 经过移植接口在具体的平台和操做系统上实现;在JVM 的上方是Java的基本类库和扩展类库以及它们的API, 利用Java API编写的应用程序 (application) 和小程序 (Java applet) 能够在任何Java平台上运行而无需考虑底层平台, 就是由于有Java虚拟机 (JVM) 实现了程序与操做系统的分离,从而实现了Java 的平台无关性。 编程
那么到底什么是Java虚拟机(JVM)呢?一般咱们谈论JVM时,咱们的意思多是: 小程序
1. 对JVM规范的比较抽象的说明; 数组
2. 对JVM的具体实现; app
3. 在程序运行期间所生成的一个JVM实例。 编程语言
对JVM规范的抽象说明是一些概念的集合,它们已经在书《The Java Virtual Machine Specification》(《Java虚拟机规范》)中被详细地描述了;对JVM的具体实现要么是软件,要么是软件和硬件的组合,它已经被许多生产厂商所实现,并存在于多种平台之上;运行Java程序的任务由JVM的运行期实例单个承担。在本文中咱们所讨论的Java虚拟机(JVM)主要针对第三种状况而言。它能够被当作一个想象中的机器,在实际的计算机上经过软件模拟来实现,有本身想象中的硬件,如处理器、堆栈、寄存器等,还有本身相应的指令系统。 函数
JVM在它的生存周期中有一个明确的任务,那就是运行Java程序,所以当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。下面咱们从JVM的体系结构和它的运行过程这两个方面来对它进行比较深刻的研究。 spa
刚才已经提到,JVM能够由不一样的厂商来实现。因为厂商的不一样必然致使JVM在实现上的一些不一样,然而JVM仍是能够实现跨平台的特性,这就要归功于设计JVM时的体系结构了。 操作系统
咱们知道,一个JVM实例的行为不光是它本身的事,还涉及到它的子系统、存储区域、数据类型和指令这些部分,它们描述了JVM的一个抽象的内部体系结构,其目的不光规定实现JVM时它内部的体系结构,更重要的是提供了一种方式,用于严格定义实现时的外部行为。在JVM specification对JVM内存的描述中,其主要包括 两个子系统——Class loader (类装载器),Execution engine(执行引擎)和 两个组件——Runtime data area (运行时数据区域),Native interface(本地接口),这几个组成的体系结构图为:Class loader:根据给定的全限定名类名 (如 java.lang.Object) 来装载class文件的内容到 Runtime data area中的method area (方法区域) 。Java程序员能够extends java.lang.ClassLoader类来写本身的Class loader
Execution engine :执行classes中的指令。任何JVM specification实现 (JDK) 的核心是Execution engine, 换句话说:Sun 的JDK 和IBM的JDK好坏主要取决于他们各自实现的Execution engine的好坏。每一个运行中的线程都有一个Execution engine的实例。
Native interface:与native libraries 交互,是其它编程语言交互的接口
Runtime data area 组件:这个组件就是JVM中的内存。
详细说明见深刻理解JVM内存模型
虚拟机经过调用某个指定类的方法main启动,传递给main一个字符串数组参数,使指定的类被装载,同时连接该类所使用的其它的类型,而且初始化它们。例如对于程序:
class HelloApp { public static void main(String[] args) { System.out.println("Hello World!"); for (int i = 0; i < args.length; i++ ) { System.out.println(args[i]); } } }
编译后在命令行模式下键入: java HelloApp run virtual machine
将经过调用HelloApp的方法main来启动java虚拟机,传递给main一个包含三个字符串"run"、"virtual"、"machine"的数组。如今咱们略述虚拟机在执行HelloApp时可能采起的步骤。
开始试图执行类HelloApp的main方法,发现该类并无被装载,也就是说虚拟机当前不包含该类的二进制表明,因而虚拟机使用 ClassLoader试图寻找这样的二进制表明。若是这个进程失败,则抛出一个异常。类被装载后同时在main方法被调用以前,必须对类 HelloApp与其它类型进行连接而后初始化。连接包含三个阶段:检验,准备和解析。检验检查被装载的主类的符号和语义,准备则建立类或接口的静态域以及把这些域初始化为标准的默认值,解析负责检查主类对其它类或接口的符号引用,在这一步它是可选的。类的初始化是对类中声明的静态初始化函数和静态域的初始化构造方法的执行。一个类在初始化以前它的父类必须被初始化。整个过程以下: