JVM运行时数据区:
包括类装载子系统、执行引擎、本地方法接口、运行时数据区。
运行数据区包括:方法区、Java堆、Java虚拟机栈、PC寄存器、运行时常量池、本地方法栈。
方法区
方法区是由所有JVM线程共享的一个公用存储区。该存储区常用于存储运行时常量池、方法数据、字段数据以及方法和函数的对于字节码。JVM规范仅仅描述了方法区的一般特性,并未规定该区域的位置,也没有指明该区域的实现方式。方法区的尺寸可以固定,也可以广大或缩小。程序员能够指定方法区的初始化尺寸,并且该区域不必是连续的。
JVM在加载class文件,创建方法区,该类中的类型信息,类(静态)变量存在于此。
类型信息包括:
这个类型的全限定名
这个类型的直接超类的全限定名(java.lang.Object除外)
这个类型的类型还是接口类型
这个类型的访问修饰符(public/abstract/final等等)
任何直接超接口的全限定名的有序列表
除了上面的基本类型信息外,还保存:
该类型的常量池(包括直接常量,如string、integer、float、point常量,和对其他类型、字段和方法的符号引用)
字段信息(字段名、字段类型、字段修饰符)
方法信息(方法名、方法返回类型、参数变量和类型、方法修饰符)
除了常量以外的所有类(静态)变量
一个类ClassLoader的引用
一个类Class类的引用
所有线程共享方法区。
方法区大小不必固定、连续、可动态调整。方法区可以在堆中自由分配,另外,JVM也可以允许用程序员指定方法区的初始化大小及最大值、最小值。
方法区可以被垃圾回收。
Java堆
堆是一个自由内存区域,常用于内存的动态分配或临时分配。堆是一种运行时数据区,为类和数组对象提供内存。JVM在启动时创建,然后当Java中创建类或数组对象时,就从堆中分配所需内存,当对象或数组不再存在后,由一个称为垃圾收集的自动存储管理系统来回收堆内存。
JVM规范中未指明堆的实现方式,以便创造各种不同的JVM实现。堆的尺寸可以在固定不变的,也可以在需要增加的的时增大或在当前尺寸过大时减小。程序员可以指定堆的初始化大小,如在win32 和Solaris系统中利用-mx命令行选项竞选指定。堆内存并不一定是连续的。如果对内存用完了,并且无法为堆分配额外的内存,习哦他能够就会产生OutOfMemoryError异常。
Java程序在运行时创建所有类实例或数组放与此。没创建一个JVM实例就有一个堆,该实例的所有线程都共享这个堆。
Java对象中包含的基本数据由它所属的类及其所有超类声明的实例变量组成。只要有对象引用,虚拟机就必须快速定位对象实例的数据。另外,他也必须通过该对象引用相应的类数据(存储于方法区的类型信息)。因此在对象中通常会有一个指向方法区的指针。
一种可能的堆空间设计就是,把对分为两部分:一个句柄池,一个对象池。一个对象引用就是一个指向句柄池的本地指针。句柄池的每一个条目有两部分:一个指向实例变量的指针,一个指向方法区类型数据的指针,这个方法有利碎片整理。
另一个设计方式是使对象直接指向一组数据,而该数据包括对象实例数据以及指向方法区中的类数据指针。因此只需要一个指针就可以访问对象的实例数据。
Java虚拟机栈
每启动一个新线程,JVM为其分配一个Java栈。其使用帧为单位保存线程的运行状态。
Java栈存储每个线程中Java方法调用的转台-包括局部变量、被调用时传进来的参数、返回值、运算中间结果。
每当线程调用一个Java方法时,虚拟机都会在该线程的Java栈中压入一个新帧。而这个新帧成为当前帧。在执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等等数据。
Java栈不连续、可指定初始化大小和最大最小值。
在JVM运行java代码的任意时刻,JVM中只要对应当前执行方法的帧是活动的。该帧称为当前帧,所代表的方法就是当前方法,而包含该方法的类则为当前类。当线程调用一个方法时(每个线程都有其自身的栈),JVM也会创建一个新帧,使该帧成为当前帧,并压到该线程的栈中。
与堆一样,JVM规范把栈帧的实现方式留到具体的JVM实现方式中。栈的尺寸可以固定,也可以根据需要扩大或缩小。程序员能控制栈的初始化尺寸和最大、最小的尺寸。
如果计算所需要的栈超出范围,那么就会产生StackOverflowError异常。
PC寄存器
JVM中的寄存器与其它计算机系统中的寄存器类似,用于反映虚拟机当前的状态。寄存器会在字节码执行时更新。其中,煮寄存器是程序计数器(PC寄存器),用于指示JVM当前执行指令的地址。如果当前执行的是本地方法(用非Java语言编写的方法),则PC寄存器的值不定。JVM中的其他寄存器包括指定当前方法的执行环境的指针、指向当前执行方法的第一个局部变量的指针,以及指向操作数栈顶的指针。
运行时常量池
运行时常量池相当于其他编程语言中所用到的符号表。顾名思义,常量池中包含的数值文字和字段常量。每个运行时常量池的内存是从方法区中分配的,JVM为类或接口加载类文件时会构造一个运行时常量池。
本地方法栈
前面提到的所有运行时数据区都是Java虚拟机规范中明确定义的,除此之外,对于一个运行中的Java程序而言,它还能会用到一些跟本地方法相关的数据区。当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。本地方法可以通过本地方法接口来访问虚拟机的运行时数据区,不止于此,它还可以做任何它想做的事情。例如,可以调用寄存器,或在堆中分配内存等。