zhaoyu@home:~$

jvm-结构

数据类型

和java类似,JVM操作两种类型的数据:基本类型引用类型。基础数据类型有整型,浮点型,returnAddress类型。boolean在JVM中使用0和表示。

returnAddress

returnAddress被JVM的jsr,ret和jsr_w指令使用。returnAddress类型的值指向jvm指令的操作码。returnAddress没有对应任何 java语言的类型,不能被java程序修改。

引用类型

有3中引用类型:类,数组,接口。他们的值指向动态创建的类实例,数组,或者实现了接口的类实例或者数组。
一个引用的值可能是null。null最初没有任何运行时类型,但是可以转换成任何类型。引用类型的默认值为null。

运行时数据区

运行时数据区结构图如下:

程序计数器(The pc Register)

每个线程都有自己的程序计数器,每个线程都会执行在某个方法的某行代码,如果这个方法不是native方法,程序计数器保存了被执行JVM指令的地址。 如果当前执行方法是native。程序计数器为undefined。

JVM 栈

JVM 栈俗称栈。每个线程拥有它私有的JVM栈,在线程创建的时候会被创建。JVM栈存放栈帧(frame),frame中保存了本地变量和部分结果。 JVM从来不会被操作,栈除了pop和push栈帧,栈帧可以直接堆分配。JVM栈的内存不需要连续。 和JVM栈关联的异常情况如下:

  • 如果要分配一个超过允许大小的JVM栈,会抛出StackOverflowError。
  • 如果JVM可以动态扩展,在扩展时或创建一个新的JVM栈时内存不足,那么会抛出一个OutOfMemoryError。

被线程共享。所有的类实例和数组的运行时内存都在堆中分配。
虚拟机启动时就会创建堆,GC负责堆中对象的内存管理,堆内存也不需要连续。

方法区

方法区也被线程共享。方法区类似于常规语言的编译代码的存储区域。它存储了每个类的数据结构,如运行时常量池,字段和方法,方法和构造方法的代码, 包括 实例初始化和接口初始化用到的特殊方法的代码。 在虚拟机启动时被创建。方法区在逻辑上是堆的一部分,java规范不强制规定方法区存放的位置和管理编译代码的策略。 内存不需要连续。

运行时常量池

运行时常量池是class文件中的constant_pool表在运行时的表示形式。它包含了从编译期的数字文本到运行时方法和字段的引用等几种类型的常量。它拥有类似 符号对照表的功能,不过它还有其他功能。
每个运行时常量池从JVM方法区中分配,当一个类或者接口被JVM创建时,运行时常量池就会被构建。

本地方法栈

本地方法栈用于支持native本地方法,不需要本地方法调用的JVM不需要提供本地方法栈。如果提供了,在创建每个线程时,通常会为每个线程分配本地方法栈。

frame

frame就是我们说得栈帧,用于保存数据和部分结果、执行动态链接、从方法返回结果及分配异常。每当一个方法被调用时,一个新的frame会被 创建。方法调用完成后,这个frame会销毁。每个栈帧拥有自己的本地变量表,自己的操作数栈,并拥有指向当前方法的类的常量池的引用。
本地变量表和操作数栈的大小在编译期时根据代码决定。
一个线程只有一个方法正在执行中,那么这个方法被称为当前方法,这个方法关联的fram被称为当前栈帧。方法关联的类被称为当前类。

  1. 操作数栈
    每个栈帧拥有一个操作数栈(LIFO),用于从本地变量表中取出数据进行运算。操作数栈的最大长度在编译期由执行的方法决定。

  2. 动态链接
    每个栈帧包含了一个运行时常量池的引用。用于支持方法代码的动态链接。class文件的代码包含了调用方法和访问变量的符号表示。 动态链接将方法的符号翻译成具体的方法引用,将变量符号转换为这些变量在运行时存储结构中对应的偏移量,必要时还需处理未定义的符号。

特殊方法(special Methods)

每个java的构造方法都表示为实例初始化方法。init由编译期提供,因为它不是一个可用的标识符,并且不能在java程序中直接使用。JVM只能通过指令 `invokespecial`调用。

class类库

JVM必须为javaSE平台的class类库的实现提供充足的支持。一些类库中的类,没有JVM的配合是无法实现的。 需要JVM特殊支持的类如下:

  • 反射相关的类,如java.lang.reflect包中的类以及Class类。
  • 一个类或接口的加载和创建,比较明显的就是ClassLoader。
  • 一个类或者接口的链接和初始化。
  • 安全相关,如java.security和其他类,如SecurityManager。
  • 多线程,如Thread类。
  • 弱引用,如java.lang.ref包中类。

上面的列举只是一种展示,具体的细节需要参考javaSE类库。