运行时数据区
java 虚拟机定义了若干种程序运行时使用到的运行时数据区
1.有一些是 随虚拟机的启动而创建,随虚拟机的退出而销毁
2.第二种则是与线程一一对应,随线程的开始和结束而创建和销毁。
java 虚拟机所管理的内存将会包括以下几个运行时数据区域
PC 寄存器
也叫程序计数器( Program Counter Register )是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器。
每一条 JVM 线程都有自己的 PC 寄存器
在任意时刻,一条 JVM 线程只会执行一个方法的代码。该方法称为该线程的当前方法( Current Method )
如果该方法是 java 方法,那 PC 寄存器保存 JVM 正在执行的字节码指令的地址
如果该方法是 native ,那 PC 寄存器的值是 undefined 。
此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。
Java 虚拟机栈
与 PC 寄存器一样, java 虚拟机栈 ( Java Virtual Machine Stack )也是线程私有的。每一个 JVM 线程都有自己的 java 虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。
虚拟机栈描述的是 Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧( Stack Frame )用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
JVM stack 可以被实现成固定大小,也可以根据计算动态扩展。
如果采用固定大小的 JVM stack 设计,那么每一条线程的 JVM Stack 容量应该在线程创建时独立地选定。 JVM 实现应该提供调节 JVM Stack 初始容量的手段。
如果采用动态扩展和收缩的 JVM Stack 方式,应该提供调节最大、最小容量的手段。
JVM Stack 异常情况:
StackOverflowError :当线程请求分配的栈容量超过 JVM 允许的最大容量时抛出
OutOfMemoryError :如果 JVM Stack 可以动态扩展,但是在尝试扩展时无法申请到足够的内存去完成扩展,或者在建立新的线程时没有足够的内存去创建对应的虚拟机栈时抛出。
Java 堆
在 JVM 中,堆( heap )是可供各条 线程共享 的运行时内存区域,也是供所有类实例和数据对象分配内存的区域。
Java 堆载虚拟机启动的时候就被创建,堆中储存了各种对象,这些对象被自动管理内存系统( Automatic Storage Management System ,也即是常说的 “Garbage Collector (垃圾回收器) ” )所管理。这些对象无需、也无法显示地被销毁。
Java 堆的容量可以是固定大小,也可以随着需求动态扩展,并在不需要过多空间时自动收缩。
Java 堆所使用的内存不需要保证是物理连续的,只要逻辑上是连续的即可。
JVM 实现应当提供给程序员调节 Java 堆初始容量的手段,对于可动态扩展和收缩的堆来说,则应当提供调节其最大和最小容量的手段。
Java 堆异常:
OutOfMemoryError :如果实际所需的堆超过了自动内存管理系统能提供的最大容量时抛出。
方法区( Method Area )
方法区是可供各条线程共享的运行时内存区域。存储了每一个类的结构信息,例如运行时常量池( Runtime Constant Pool )、字段和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法
方法区在虚拟机启动的时候创建。
方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。
方法区在实际内存空间中可以是不连续的。
Java 虚拟机实现应当提供给程序员或者最终用户调节方法区初始容量的手段,对于可以动态扩展和收缩方法区来说,则应当提供调节其最大、最小容量的手段。
Java 方法区异常:
OutOfMemoryError : 如果方法区的内存空间不能满足内存分配请求,那 Java 虚拟机将抛出一个 OutOfMemoryError 异常。
运行时常量池( Runtime Constant Pool )
运行时常量池是每一个类或接口的常量池( Constant_Pool )的运行时表现形式,它包括了若干种常量:编译器可知的数值字面量到必须运行期解析后才能获得的方法或字段的引用。
运行时常量池是方法区的一部分。 每一个运行时常量池都分配在 JVM 的方法区中,在类和接口被加载到 JVM 后,对应的运行时常量池就被创建。
在创建类和接口的运行时常量池时,可能会遇到的异常:
OutOfMemoryError :当创建类和接口时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大内存空间后就会抛出 OutOfMemoryError
本地方法栈
Java 虚拟机可能会使用到传统的栈来支持 native 方法(使用 Java 语言以外的其它语言编写的方法)的执行,这个栈就是本地方法栈( Native Method Stack )
如果 JVM 不支持 native 方法,也不依赖与传统方法栈的话,可以无需支持本地方法栈。
如果支持本地方法栈,则这个栈一般会在线程创建的时候按线程分配。
异常情况:
StackOverflowError :如果线程请求分配的栈容量超过本地方法栈允许的最大容量时抛出
OutOfMemoryError :如果本地方法栈可以动态扩展,并且扩展的动作已经尝试过,但是目前无法申请到足够的内存去完成扩展,或者在建立新的线程时没有足够的内存去创建对应的本地方法栈,那 Java 虚拟机将会抛出一个 OutOfMemoryError 异常。