Java虚拟机是由一个规范来定义的抽象计算机。
抽象的规范
具体的实现
运行中的虚拟机实例
每个java程序都运行于它自己的虚拟机实例中。
Java虚拟机的结构分为:类装载子系统,运行时数据区,执行引擎,本地方法接口。其中运行时数据区又分为:方法区,堆,Java栈,PC寄存器,本地方法栈。
每个java虚拟机实例都有一个方法区和一个堆,由该虚拟机实例中所有线程所共享,对方法区的访问必须设计成线程安全。
Java程序在运行时创建的所有类实例或数组放与此。每创建一个JVM实例就有一个堆,该实例的所有线程都共享这个堆。
Java对象中包含的基本数据由它所属的类及其所有超类声明的实例变量组成。只要有对对象引用,虚拟机就必须快速定位对象实例的数据。另外,他也必须能通过该对象引用访问相应的类数据(存储于方法区的类型信息)。因此在对象中通常会有一个指向方法区的指针。
一种可能的堆空间设计就是,把堆分为两部分:一个句柄池,一个对象池。一个对象引用就是一个指向句柄池的本地指针。句柄池的每个条目有两部分:一个指向实例变量的指针,一个指向方法区类型数据的指针。这种方法有利碎片整理。但每次访问对象实例变量都得进行两次指针转换。
另一个设计方式是使对象指针直接指向一组数据,而该数据包括对象实例数据以及指向方法区中的类数据指针。因此只需一个指针就可以访问对象的实例数据。当虚拟机为了减少内存碎片而移动对象时,必须在整个运行时数据区中更新指向被移动对象的引用。
每个对象都可以有一个方法表,可以加快调用实例方法时的效率。Java虚拟机规范并不要求必须有。
方法区中存放被装载的类型信息,该类型中的类(静态)变量同样也是存储在方法区中。方法区大小可以在堆中自由分配,方法区可以被垃圾回收。
类型信息包括:
这个类型的全限定名。
这个类型的直接超类的全限定名(除非是java.lang.Object,无超类)
这个类型是类类型还是接口类型。
这个类型的访问修饰符(public,abstract
...)
任何直接超接口的全限定名的有序列表
除了上面列出的基本类型信息外,虚拟机还为每个被装载的类型存储以下信息:
该类型的常量池
字段信息
方法信息
除了常量以外所有类(静态)变量
一个到类ClassLoader的引用
一个到Class类的引用
每创建一个线程,都将有该线程自己的PC寄存器及一个java栈,每个线程只能访问自己的PC寄存器和java栈,该线程如果正在执行一个java方法,则PC寄存器的值是下一条被执行的指令;java栈使用帧为单位保存线程的运行状态。
Java栈存储每个线程中Java方法调用的状态—包括局部变量,被调用时传进来的参数,返回值,运算中间结果。
每当线程调用一个Java方法时,虚拟机都会在该线程的Java栈中压入一个新帧。而这个新帧成为当前帧。在执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等等数据。Java栈不连续,可指定初始大小和最大最小值。
Java方法可以以两种方式完成:正常返回return;通过抛出异常而中止。
Java虚拟机的两种类装载器:启动类装载器和用户自定义类装载器。主要任务有:
装载---查找并装载类型的二进制数据
连接---执行验证,准备,以及解析(可选)
验证:确保被导入类型的正确性
准备:为类变量分配内存,并将其初始化为默认值
解析:把类型中的符号引用换为直接引用
初始化---把类变量初始化为正确的初始值
每个Java虚拟机都必须实现一个启动类装载器。
用户自定义类装载器,尽管用户自定义类装载器是Java程序的一部分,但类ClassLoader中的四个方法是通往Java虚拟机的通道:
protected final Class<?> defineClass(String name, byte[] b, int off, int len);
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain);
protected final Class<?> findSystemClass(String name);
protected final void resolveClass(Class<?> c);
任何java虚拟机实现都必须把这些方法连到内部的类装载器子系统中。
两个重载的defineClass() 方法,接受一个byte[] b的字节数组作为输入参数,在b[off]到b[off + len]之间的二进制数据必须符合java class文件格式,class文件即线性二进制数据流。name参数指定类型的全限定名,前一个defineClass将给类型赋以默认的保护域,后一个类型保护域由protectionDomain指定。
findSystemClass()使用系统类装载器装载指定类型。
resolveClass()对class实例表示的类型进行连接,defineClass()只是对类型进行装载