一、根据《Java 虚拟机规范(Java SE 7版)》规定,Java虚拟机所管理的内存将会包括一下几个运行时数据区域:
1. 程序计数器
程序计数器是一块较小的内存空间,当前线程所执行的字节码的行号指示器。字节码解释器工作就是通过改变这个计数器的值来选取下一条所执行的字节码指令。JVM的多线程是通过线程轮流切换并分配处理器的执行方式来实现的,在任何一个确定时刻,一个处理器只会执行一条线程中的指令。
每条线程都有一个独立的程序计数器,线程私有的内存。
如果线程正在执行的是一个JAVA方法,这个计数器记录的是正在执行的虚拟机字节码指令地址。如果正在执行的是native方法,这个计数器值则为空。此内存区域是唯一一个在JVM规范中没有规定任何OutOfMemoryError情况的区域。
2. Java虚拟机栈
线程私有的,生命周期与线程相同。Java虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,对应一个栈帧在虚拟机中从入栈到出栈的过程。
局部变量表存放了各种基本类型、对象引用和returnAddress类型(指向了一条字节码指令地址),所需的内存空间在编译期间完成分配。当进入一个方法时,这个方法需要在栈中分配多大的局部空间是完全确定的,在运行期间不会改变局部变量表的大小。
规定的异常情况有两种:1. 线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverMemory异常。2. 如果虚拟机可以动态扩展,当扩展时无法申请到足够的内存,就抛出OutOfMemoryError异常。
3. 本地方法栈
为虚拟机使用到的native方法服务。本地方法栈区域也会抛出StackOverMemory和OutOfMemoryError异常。
4. Java堆(GC堆)
5. 方法区
所有线程共享的内存区域,存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。内存回收目标主要针对常量池的回收和类型的卸载。
根据JVM规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
6. 运行时常量池
方法区的一部分。用于存放编译期生成的各种字面量和符号引用,在类加载后存放到方法区的运行时常量池中。
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。