本文按
一. 什么是Java虚拟机
二. 虚拟机的生命周期
三. Java虚拟机结构
四. 数据类型( Data Types)
五. 字大小
六. Class Loader 系统
一. 什么是Java虚拟机
Java虚拟机包括以下几个方面的内容:
(1) 抽象规范
(2) 具体实现
(3) 运行时实例
虚拟机抽象规范是一个概念,具体描述在The Java Virtual Machine Specification里。 虚拟机具体实现在很多平台上,很多软件或者硬件厂商都提供了不同的虚拟机实现。运行实例是一个独立运行的java应用。
二. 虚拟机的生命周期
虚拟机的运行实例有很清晰的生命周期。
(1) 当一个Java应用启动时,运行时实例产生;
(2) 当应用结束时,运行时实例消亡;
(3) 如果在同一台主机的同一个虚拟机上运行多个应用,将会得到多个不同的实例;
Java虚拟机实例通过调用main()方法开始运行,main()方法必须是public, static, return void, 并且接受一个参数:String[]。 任何带有这样的main()方法的Java应用可以被看做程序运行的入口。
class Echo {
public static void main(String[] args) {
int len = args.length;
for (int i = 0; i < len; ++i) {
System.out.print(args[i] + " ");
}
System.out.println();
}
}
在Java虚拟机内部有两种线程:守护线程和非守护线程。守护线程是Java虚拟机的自有线程,比方说垃圾回收线程。应用可以把任何线程标记为守护线程,main()线程是非守护线程。
在有任意一个非守护线程执行的情况下,Java应用都会继续执行。当所有的非守护线程终止后,应用退出。Java应用也可以调用exit()方法退出。
三. Java虚拟机结构
3.1 虚拟机整体结构
下图展示了虚拟机结构:
class loader subsystem:负责加载类和接口
execution engine:负责执行加载的类中的方法
runtime data area: 当虚拟机运行程序的时候,负责在内存中存储数据:包括:二进制代码,对象,方法参数,返回值,本地变量以及中间结果等。
3.2 关于Runtime Data Area
- 每一个虚拟机实例都有一个方法区(method area)和一个堆(heap),这两个区域被虚拟机中所有运行的线程共享,当虚拟机加载一个类文件(class file)的时候,将从二进制数据中解析的类型信息放进method area,随着程序的运行,虚拟机将产生的对象放入到堆。
- 随着新线程的不断创建,每一个新线程会拥有自己的程序计数器(pc register)和Java栈(stacks)
如果线程正在执行一个Java方法,pc register的值代表下一个将要执行的指令。
1> 一个线程的Java栈存贮着Java方法的调用状态,状态包括它的本地变量,参数,返回值 和中间结果。
Java栈由栈帧(stack frames)组成,栈帧中存储Java方法的调用状态,每当线程invoke一个方法的时候,虚拟机将一个stack frame push到当前这个线程的栈中,当这个方法执行完成后,虚拟机pop出这个栈帧病丢弃。
2> 本地方法调用的实现方式在native method stacks中。
Java虚拟机没有寄存器存储中间值,指令集使用Java Stack存储中间值。这种基于栈的虚拟机指令集有助于促进代码优化。
下图中描述了内存中Java虚拟机线程的创建。这个区域对于每个线程是私有的,任何线程不能访问其他线程的程序计数器。
这个图展示了一个三个线程运行的虚拟机实例快照,在这个快照中,thread1 和 thread2正在执行Java方法。Thread3正在执行本地方法。
四. 数据类型( Data Types)
Java数据类型包含基本数据类型和引用数据类型,此处不想过多介绍,使用下图描述虚拟机数据类型家族中的成员 :
4.1 虚拟机中的基本数据类型
所有编程语言中的基本数据类型对虚拟机也是基本数据类型。尽管boolean是一个基本数据类型,但是指令集对它的支持非常有限。当编译器把java源代码编译成二进制代码的时候,会把它转化成int或者byte来表示true-1 false -0; 使用boolean的操作符用int; boolean数组被编译为byte[].
Java语言中出了boolean以外的数据类型,在虚拟机中使用numeric types来表示。Numeric type包含两种:
(1) integral types: byte, short, int, long, and char
(2) floating- point types: float and double
Java虚拟机和Java语言中同一个数据类型具有相同的范围,比如一个long在虚拟机中是64-bit的有符号补码。
Note : Java虚拟机还有一个特殊的基本数据类型:returnAddress type。用来补充finally子句的。
4.2虚拟机中的引用类型
虚拟机中的引用类型名称为reference。引用类型的值有3种: class type,interface type, 和the array type。所有这三种类型都设计到动态对象的创建。Class type的值指向class实例,array type的值指向array, interface type的值指向interface的实现类的实例。
Note:还有一种引用值是null,表示一个引用没有指向任何实例。
Java虚拟机规范定义了每种数据类型的范围,但是并没有定义他们的大小。下图展示了每种数据类型的范围。
五 字大小
Java虚拟机中最基本的数值单元是字。字必须足够大来表示byte, short, int, char, float, returnaddress 和 reference。 两个字必须足够大来表示long和double。通常选择一个字的大小为32位。
六 Class Loader 系统
Java虚拟机包含两种class loader:a bootstrap class loader 和user-defined class loaders。
Bootstrap class loader是虚拟机实现的一部分,user-defined class loaders是Java应用的一部分。不同的classloader把类加载到虚拟机不同的命名空间(name space)上。
Classloader子系统涉及到许多其它虚拟机部分和许多来自于java.lang library的类。比方说用户自定义的classloader通常会继承自java.lang.ClassLoader类。ClassLoader中的方法允许Java应用访问虚拟机中类加载机制。同时在任何类型的虚拟机中可以创建java.lang.Class的实例来代表类型信息。和其它对象一样class对象也存储在堆上。
6.1 类加载(loading),连接(linking) 和初始化(Initialization)
class loader子系统不光需要定位和导入二进制数据,还需要对数据进行校验,初始化内存等。
(1) Loading: 为一个Type找到并且导入二进制数据
(2) Linking: 执行校验(verification),准备(preparation)和转换(resolution)
a. verification: 确保类型正确
b. Preparation:为类中的变量开辟空间,将内存中的数据初始化到默认值
c. Resolution: 将符号引用转变为直接引用
(3) Initialization:调用Java代码初始化类变量
6.2 Bootstrap Class Loader
Java虚拟机的实现必须要能够加载类和接口的二进制文件,这些文件被严格按照一定的格式定义。在早期的Java 虚拟机(Sun’s 1.1 JDK)实现中,虚拟机会以环境变量下的CLASSPATH作为class文件的根路径,然后再按照子路径去找。在JDK1.2中做了修改,自动添加了用户自定义classloader。
6.3 用户自定义classloader(User-Defined Class Loaders)
尽管用户可以定义自己的classloader, 但是只能通过ClassLoader下面的几个方法:
// Four of the methods declared in class java.lang.ClassLoader:
protected final Class defineClass(String name, byte data[],
int offset, int length);
protected final Class defineClass(String name, byte data[],
int offset, int length, ProtectionDomain protectionDomain);
protected final Class findSystemClass(String name);
protected final void resolveClass(Class c);