1、程序计数器/PC寄存器(the PC Register)
程序计数器 -- 用于指定字节码解析器吓一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
Java 虚拟机可以同时支持多个执行线程 。每个 Java 虚拟机线程都有自己的 pc (程序计数器) 寄存器。在任何时候, 每个 Java 虚拟机线程都在执行单个方法的代码, 即该线程的当前方法。如果该方法不是本机方法, 则 pc 寄存器包含当前正在执行的 Java 虚拟机指令的地址。如果线程当前执行的方法是本机的, 则 Java 虚拟机的 pc 寄存器的值是未定义的(undefined)。Java 虚拟机的 pc 寄存器足够宽, 可以在特定平台上保存返回地址或本机指针。
2、Java 虚拟机栈(Java Virtual Machine Stacks)
Java 虚拟机栈与程序计数器一样,Java 虚拟机栈也是线程私有的,它与线程的生命周期是一致的。每个Java虚拟机线程都有一个自己私有的Java 虚拟机栈,该虚拟机栈在线程创建的同时被创建。Java 虚拟机栈类似于传统的语言(例如C语言)的栈。它包含局部变量和部分结果, 并在方法调用和返回中发挥作用。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的时候都会创建一个栈帧用于存储局部变量表、操作数、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中从入栈到出站的过程。由于 Java 虚拟机堆栈从不直接操作, 除非是推送和弹出帧,因此Java 虚拟机堆栈的内存不需要是连续的,可以对帧进行堆分配。
局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress类型。局部变量表所需的内存空间在编译期间完成分配。当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
Java虚拟机栈可能存在两种异常情况:
1)StackOverflowError 异常:
如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出 StackOverflowError 异常;
2)OutOfMemoryError 异常:
如果虚拟机可以动态扩展,而在扩展的时候无法申请到足够的内存,就会抛出OutOfMemoryError 异常。
3、本地方法栈(Native Method Stacks)
本地方法栈与虚拟机栈的区别是:虚拟机栈为虚拟机执行Java方法(使用Java编写的方法--字节码)服务;而本地方法栈则为虚拟机使用到的Native 方法(使用非Java语言编写的方法)服务。
Java 虚拟机的实现可以使用传统的堆栈 (俗称 "C 堆栈") 来支持本机方法 (用 Java 编程语言以外的语言编写的方法)。本机方法堆栈也可用于实现 Java 虚拟机指令集的解释器, 语言 (如 C)。Java 虚拟机实现不能加载本机方法并且本身不依赖于常规堆栈,不需要提供本机方法堆栈。如果提供, 则在创建每个线程时, 通常会为每个线程分配本机方法堆栈。如果该方法不是本机方法, 则 pc 寄存器包含当前正在执行的 Java 虚拟机指令的地址。如果线程当前执行的方法是本机的, 则 Java 虚拟机的 pc 寄存器的值是未定义的。Java 虚拟机的 pc 寄存器足够宽, 可以在特定平台上保存返回地址或本机指针。
本地方法栈与Java虚拟机栈类似也会产生StackOverflowError 和 OutOfMemoryError异常。
4、堆(Head)
Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的堆。堆是分配给所有类实例(对象)和数组的运行时数据区域。
堆是在虚拟机启动时创建的。对象的堆存储由自动存储管理系统 (称为垃圾回收器) 回收;对象永远不会显式释放。Java 虚拟机没有特定类型的自动存储管理系统, 可以根据实现者的系统要求选择存储管理技术。堆可以是固定大小的, 也可以根据计算的要求进行扩展, 如果没有必要使用较大的堆, 则可以收缩堆。堆的内存不需要是连续的。堆是Java GC 垃圾收集器管理的主要区域。
Java 虚拟机可以为程序员或用户提供对堆初始大小的控制,如果堆可以动态展开或收缩, 则控制最大和最小堆大小。
以下特殊情况与堆相关联:
如果计算所需的堆数超过了自动存储管理系统所能提供的堆, 则 Java 虚拟机将引发 OutOfMemoryError
5、方法区(Method)
方法区和堆一样,在所有 Java 虚拟机线程之间共享。方法区域类似于常规语言的编译代码的存储区域, 也类似于操作系统进程中的 "文本" 段。它存储着每个类结构, 譬如运行时常量池、字段和方法数据, 以及方法和构造函数的代码, 包括类中使用的特殊方法和实例初始化以及接口初始化。方法区域是在虚拟机启动时创建的。尽管方法区域在逻辑上是堆的一部分, 但可以选择不进行垃圾收集或压缩垃圾。
方法区域可以是固定大小的, 也可以根据计算的要求进行扩展, 如果没有必要使用更大的方法区域, 则可以收缩。方法区域的内存不需要是连续的。
如果计算所需的方法区域超过了自动存储管理系统所能提供的方法区域, 则 Java 虚拟机将引发 OutOfMemoryError
6、运行时常量池(Run-Time Constant Pool)
运行时常量池是方法区的一部分。运行时常量池是类文件中常量池表的每个类或每个接口的运行时表示形式。它包含多种类型的常量, 从编译时已知的数字文本到必须在运行时解析的方法和字段引用。运行时常量池的功能类似于传统编程语言的符号表, 尽管它包含的数据范围比典型的符号表更广泛。每个运行时常量池都从 Java 虚拟机的方法区域中分配而来。类或接口的运行时常量池是在 Java 虚拟机创建类或接口时构造的。
创建类或接口时, 如果构造运行时常量池所需的内存超过了 Java 虚拟机的方法区域中可用的内存, 则 Java 虚拟机将引发 OutOfMemoryError。
网友评论