运行时数据区 (Run-Time Data Areas)
Java虚拟机在程序执行期间定义了各种
运行时数据区,一部分数据区的生命周期与Java虚拟机一致,另一部分数据区的生命周期与线程一致。
1. 程序计数器 (program counter register)
- 程序计数器是线程私有的,生命周期随线程而生而灭。
- 在任何时候,每个线程都在执行一个方法。如果该方法是native方法,程序计数器会存储当前jvm指令的内存地址。反之,程序计数器的值将不会被定义。
- 程序计数器(空间)足够大,可以保存一个returnAddress类型的值或者特定平台上的本地指针。
2. Java虚拟机栈 (java virtual machine stacks)
- Java虚拟机栈是线程私有的,生命周期随线程而生而灭。
- Java虚拟机栈的使用的内存可以是不连续的。
- Java虚拟机栈存储栈帧。每个方法从调用到执行完成的过程,对应着一个栈帧在Java虚拟机栈中的压栈到弹栈的过程。
- Java虚拟机栈可以具有固定大小,也可以根据计算要求动态扩展或收缩。
- 如果Java虚拟机允许动态扩展,但是扩展时却无法申请到足够的内存,则会抛出OutOfMemoryError异常。
- 如果线程请求分配的栈容量大于Java虚拟机栈允许的最大容量,则会抛出StackOverflowError异常。
3. 堆 (heap)
- 堆存储对象实例。
- 堆内存可以是不连续的。
- 堆是线程共享的,生命周期与Java虚拟机一致。
- 堆可以是固定大小,也可以根据需求动态扩展和收缩。
- 只要Java虚拟机中的对象不断被创建,且保证GC Roots到对象之间有可达路径来避免垃圾回收机制,当堆存储的对象到达堆内存允许的最大容量时,会抛出OutOfMemoryError异常。
4. 方法区 (method area)
- 方法区是线程共享的,生命周期与Java虚拟机一致
- 方法区存储类信息,运行时常量池(runtime constant pool),字,方法数据,JIT编译后的代码数据,以及类和接口初始化的函数<clinit>和类实例初始化的函数<init>等信息。
- 方法区在逻辑上是堆的一部分,但是两者应该区分来看。
- 方法区的内存区域可以是不连续的。
- 方法区的大小可以是固定的,也可以根据需求动态的扩缩容。
- 如果无法提供方法区中的内存来满足分配的请求,会抛出OutOfMemoryError异常。
5. 运行时常量池 (runtime constant pool)
- 每个运行时常量池都是从Java虚拟机的方法区中分配的
- 运行时常量池主要用于存放编译期生成的各种字面量和符号引用,以及在运行时解析的方法和字段引用。
- 创建类或接口时,如果运行时常量池构造所需的内存超过Java虚拟机的方法区域中可用的内存,则Java虚拟机将抛出OutOfMemoryError
6. 本地方法栈 (native method stacks)
- 本地方法栈和Java虚拟机栈很相似。
- 本地方法栈也是线程私有的,并且也能抛出OutOfMemoryError,StackOverflowError异常。
- 本地方法栈为虚拟机使所使用到的native方法服务。
- Java虚拟机中并没有限制实现native方法的语言,使用方式和数据结构,因此具体的虚拟机可以自由的实现它。
- 有的虚拟机(Sun HotSpot虚拟机)直接把本地方法栈和虚拟机栈合并在一起
 
                     
                     
                        
                        