平台无关
平台无关性对于减化了移植大量工作。
Jini技术能够通过网络能够彼此交换对象。
java平台无关性减少部署应用程序成本。
网络特性
java体系可以架构易于扩展和维护的分布式结构。
java虚拟机定义
抽象规范 仅仅是一个概念
一个具体实现 来自多个厂商存在多个平台
一个运行中的虚拟机 运行一个java程序的同时,也就在运行一个java虚拟机实例
生命周期
启动一个java程序时,虚拟机实例也就诞生,该程序退出,虚拟机实例也就随之消亡。
java虚拟机内部两种线程 守护与非守护
所有非守护进程终止时,java虚拟机实例也将退出。
java虚拟机体系结构
<图>
java虚拟机运行一个java程序时,需要内存来存储比如字节码,从己装载的class文件中得到其他信息,程序创建对象,传递给方法的参数,返回值,局部变量,以及运算的中间结果等等,
把它们组织到几个”运行时数据区中”。
一个java虚拟机实例中个所有线程共享方法区和堆,每个线程会创建自己的java栈和PC寄存器.
数据类型
java虚拟机是通过某些数据类型来执行计算。
数据类型可分两种-基本类型和引用类型
字长
java虚拟机中最基本的单元就是字,它的大小是由每个虚拟机实现的设计者来决定。java虚拟机规范中,关于运行时数据区的大部分内容都是基于“字”这个抽象概念。比如,关于栈帧的两个部分-局部变量和操作数栈-都是按“字”来定义的。
类装载器-启动类和用户自定义两种类型
对于每一个被装载的类型,java虚拟机都会为它创建一个java.lang.Class对象实例放在堆中,而装载的类型信息放在方法区中。
装载-查找并装载类型的二进制数据
连接-执行验证,准备,以及解析
验证:确保被导入类型的正确性
准备:为类变量分配内存,并将其初始化默认值
解析:把类型中的符号引用转换为直接引用。
初始化-类变量初始化正确的值
ClassLoader-
defineClass
defineClass 每个java虚拟机的实现都必须保证ClassLoader. defineClass ()
将新类型导入到方法区
findSystemClass 装载指定类型,并返回Class对象
resoveClass 对Class实例表示的类型执行连接。
方法区
被装载的类型信息存储在一个被称为方法区的内存中,并且所以线程共享方法区中的数据。方法区也可以被垃圾收集。当某个类不再被引用的类时,java虚拟机可以卸载这个类。
对于每个装载的类型,虚拟机都会在方法区中存储下类型信息
这个类型的全限定名
这个类型的直接超类的全限定名
类型是类还是接口
类型的访问修饰符
直接超类接口全限定名
类的常量池 虚拟机必须为每一个被装载的类型维护一个常量池。池中的数据项就像数组一样通过索引访问。
字段
方法
类变量
ClassLoader引用
Class引用
常量池
字段信息 字段名 字段类型 字段修饰符 方法名 返回值类型 方法参数 修改符
不是抽象和本地方法则
方法的字节码
操作数栈和方法栈帧的局部变量区的大小
异常表
类变量
编译时常量
方法表 虚拟机为每个非抽象类,都生成一个方法表,把它作为类信息的一部分保存在方法区。方法表是一个数组,它的元素是所有它的实例可能被调用的实例方法的直接引用,运行时可以通过方法表快速搜寻对象中调用的实例方法。
堆
每个对象的数据都包含一个指向特殊数据结构的指针,这个数据结构位于方法区,包括两个部分:一个指向方法区对应类数据的指针,此对象的方法表。
方法表指向的实例方法数据包括以下信息:
此方法的操作数栈和局部变量区大小
此方法的字节码
异常信息
对象锁,等待方法wait,notify notifyAll
垃圾收集器数据
数组内部表示
程序计数器
每一个线程都有一个自己的寄存器,它有一个字长,能够持有一个本地指针,和returnAddress。线程执行某个java方法时,PC寄存器内容总是指向下一条将被执行的执行指令地址,如果线程执行一个本地方法,那么值为undefined
java栈
每当启动一个新线程时,java虚拟机都会为它分配一个java栈。java栈以帧为单位保存线程运行状态。每当调用线程的一个方法时,虚拟机会在该线程中压入一个新帧。当一个线程调用一个方法时,方法的局部变量保存在调用线程java栈帧中。
栈帧
三部分组成:局部变量区,操作数栈和帧数据区。
当线程调用java方法时,虚拟机从对应的类信息中得到此方法的局部变量区和操作数栈的大小,并据此分配栈帧的内存,然后压入java栈中。
局部变量
被组织为一个以字长为单位,从0开始计数的数组。int float reference returnAddress占据一项,byte,short,char的值在存入数组前都被转换为int值,因而同样占据一项。long和double的值在数组中却占据连续两项。局部变量区包含了对应的方法的参数和局部变量。编译器首先按声明的顺序把这些参数放入局部变量数组。
操作数栈
和局部变量一样,操作数栈也是被组织成一个字长为单位的数组。不是通过索引而是通过标准的栈操作来访问。虚拟机在操作数栈中存储数据的方式和在局部变量中是一样的。java虚拟机的指令是从操作数栈中而不是寄存器中取得操作数的。虚拟机操作数栈作为工作区大多数操作指令要从这里弹出数据,执行运算,然后把结果压回操作数栈。
帧数据区-常量池解析,正常返回以及异常派发机制的信息保存在帧数据区。
本地方法栈
本地方法可能通过本地方法接口来访问虚拟机的运行时数据区。线程调用java方法时,虚拟机会创建一个新的栈帧并压入java栈。然而当它调用的是本地方法时,虚拟机会保持java栈不变,不再线程的java栈中压入新的帧,虚拟机只是简单地动态连接并直接调用指定的本地方法。
执行引擎
执行引擎的行为使用指令集来定义。
抽象规范 使用指令集规定了执行引擎的行为
一个具体实现 多种不同技术
一个正在运行的实例 一个线程
运行中的java程序的每一个线程都是一个独立的虚拟机执行引擎的实例。从线程生命周期到结束,它要么在执行字节码,要么在执行本地方法。所有属于用户运行程序的线程,都是实际工作的执行引擎。
指令集 方法的字节码流由java虚拟机指令序列构成,每一条指令包含一个单字节的操作码,后面跟随0个多个操作数。
当虚拟机执行一条指令时,可能使用当前常量池中的项,当前帧的局部变量中的值,当前帧操作数栈顶端的值。
执行引擎取得操作码,如果有操作数一并取得。执行操作码和跟随的操作数规定的动作,然后再取得下一个操作码。这个执行字节码的过程在线程完成前将一直持续,通过从它的初始化方法返回,或者没有捕获抛出的异常都可以标示线程得结束。
执行技术 解释,即时编译,自适应优化,芯片级直接执行,
本地方法接口
Sun java本地接口,或者称作JNI,是为可移植性准备的。JNI设计的可以被任何java虚拟机实现支持,而不管它们使用何种垃圾收集或者对象表示技术。这样它能使开发者在一个特定的主机平台上,把同样的(与JNI兼容)本地方法二进制形式连接到任何支持JNI的虚拟机实现上。
实现设计者可以选择创建一些私有的本地方法接口,扩展或者取代JNI。为了实现可移植性,JNI在指针和指针之间,指针和方法之间使用了很多间接方法。
本地方法必须能够和java虚拟机实例的某些内部状态有某种程序的交互。本地方法接口允许本地方法完成下面部分工作:
传递或返回数据。
操作实例变量或者调用使用垃圾收集的堆中的对象方法
操作类变量或者调用类方法
操作数组
对堆中的对象加锁,以便被当前线程独占使用。
在使用垃圾收集的堆中创建新的对象
装载新的类
抛出新的异常
捕获本地方法调用的java方法抛出的异常
捕获虚拟机抛出的异步异常
指示垃圾收集器某个对象不再需要
如果实现的垃圾收集器为了减少堆碎片移动了一个对象,本地方法设计必须保证下面二者之一:
当对象的引用被传递给一个本地方法后,它可以移动。
任何其引用传递给本地方法的对象都被钉住,真到本地方法返回,或者它表明自己已经完成了对象操作。