Java内存区域
Java内存区域
JVM的内存区域包含六大运行时区域
程序计数器(Pragram Counter Register)
程序计数器是相对较小的一块内存空间,可以当作是当前线程所执行的字节码的行号指示器。也就是说字节码解析器可以通过改变计数器的值来选择下一条需要执行的字节码指令,我们常见的分支(if)、循环(for)、异常处理、线程恢复等基本功能都需要程序计数器的支持。 由于程序计数器描述的是当前线程的指示器,那么在多线程情况下,每个线程都会拥有一个独立存储、互不影响的计数器来记录之前执行的位置,当线程切换后能正确恢复到正确的执行位置,因而程序计数器是线程私有的内存区域。 在Java虚拟机规范中,程序计数器是唯一一块没有规定任何OutOfMemoryError的 内存区域。 线程执行Java方法时,计数器记录的值是正在执行的虚拟机字节码指令的地址;线程执行本地方法时,计数器记录的值则为空(Undefined)。
虚拟机栈(Virtual Machine Stack)
Java虚拟机栈描述的是Java方法执行的内存模型,每个方法执行的时候都会创建一个用于存储局部变量、操作数栈、动态链接等信息的栈帧(Stack Frame),每个方法从调用到执行完成的过程对应栈帧在虚拟机栈中从入栈到出栈。因而他是线程私有的一块内存区域,它的生命周期与线程相同。 在Java虚拟机栈中,虚拟机栈中定义了两类异常。当虚拟栈动态扩展时,如果虚拟机栈无法满足扩展所需的内存,就会抛出OutOfMemoryError异常;如果线程请求的栈深度大于虚拟机所允许的栈深度时,将会抛出StackOverflowError异常.
*本地方法栈(Native Method Stack)**
本地方法栈与虚拟机栈的作用非常类似,区别在于本地方法栈为虚拟机的Native方法服务,而虚拟机栈则是为虚拟机执行Java方法(字节码)服务,部分虚拟机讲本地方法栈和虚拟机栈合二为一。本地方法栈同样也存在两种异常情况:StackOverflowError、OutOfMemoryError。
堆(Heap)
Java堆是在虚拟机启动时所创建的运行时数据区中最大的、被所有线程共享的、用于存放对象实例的内存区域。但随着逃逸技术与JIT编译器的发展,并非所有的对象都分配在堆上。 Java堆也是垃圾收集器中最主要的区域,因此又被称之为“GC堆”(Garbage Collected Heap). 根据Java虚拟机规范的规范,Java堆允许内存在物理上不连续,只需在逻辑上连续即可,既可以设置成固定的大小,也可以通过命令(Xms、Xmx)来进行动态扩展,如果在堆中没有内存完成分配,并且Java堆也无法进行扩展,此时就会抛出OutOfMemorryError异常。
方法区(Method Area)
方法区和Java堆一样,都是被线程共享的内存区域,方法区用于存放已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。方法区不仅允许内存上的不连续,还可以选择不实现垃圾收集操作,但由于这块内存常被人称为“永久代”区域,即存放经过多次回收后没有被回收的数据,这就导致数据所需的内存大于允许的内存时,就会抛出OutOfMemorryError异常,因而这部分还是需要进行回收操作的。不过在Java8之后,虚拟机开发团队将这块区域取消了。
运行时常量池(Runtime Constant Pool)
运行时常量池属于方法区的一部分,它用于存放编译器所生产的各种字面量和符号引用,将在类加载后进入方法区的运行时存放。 运行时常量池相对于Class文件常量池有两个特性,一个是动态性、另一个时能把翻译后的直接引用存储在运行时常量池中。 既然是方法区的一部分,自然受到方法区的限制,当常量池无法再申请到内存时就会抛出OutOfMemorryError异常。