Java虚拟机自动内存管理机制之内存区域与内存异常

Java虚拟机的内存区域与内存异常

初学过Java的大致知道Java有一个堆内存,有一个栈内存。然后栈是存放引用,堆用来存放对象实例。可能简单的一句话就概括了jvm的内存区域。很显然jvm的内存区域要比这个划分精细得多。在jvm中运行时数据区,jvm的内存分配区域有程序计数器、Java虚拟机栈、本地方法栈、Java堆、运行时常量池、方法区、直接内存。对于每一个区域为什么这么划分,为什么不是直接使用堆栈就可以,当然这还涉及到jvm的垃圾回收机制、类加载机制、类加载的过程。

运行时数据区划分图

Java虚拟机自动内存管理机制之内存区域与内存异常

程序计数器

取字节码指令,执行。它是线程私有的,每一条线程都有一个独立的程序计数器。通常程序计数器的内存可以忽略,这部分的区域不会发生内存溢出。
Java虚拟机栈,java虚拟机栈线程私有,对于每一个方法,java虚拟机都会创建一个独立的栈帧,用于存放局部变量表,操作数,方法出口等信息。局部变量表中包括基本的数据类型和引用类型。在java虚拟机栈中,如果线程请求栈的深度大于虚拟机允许的深度,会出现*Error异常。如果虚拟机栈可以动态扩展,无法申请到足够的内存时会出现OutOfMemmoryError异常。

本地方法栈

与虚拟机栈唯一的不同点在于虚拟机执行java方法(字节码),本地方法栈是native方法。

Java堆

java堆是java内存区域中最大的一块,线程共享的。几乎所有的对象实例都在java堆上分配内存,但并不是所有的对象都在java堆上分配。随着JIT编译技术的程序,逃逸分析技术的程序,栈上分配,标量替换优化技术导致微妙的变化。Java堆的内存回收通常也是基于分代的,通常划分为新生代和老年代,对于新生代和老年代,通常新生代分为Eden区,Survivor区,Survivor区又分为,from survivor区和to survivor区。线程共享的java堆中还会划分多线程分配缓冲区(TLAB)。

方法区

方法区与java堆一样也是线程共享的。对于方法区它用于存储已经被虚拟机加载的类信息,常量、静态变量及时编译后的代码数据。
运行时常量池,属于方法区的一部分,主要用于存储编译时期各种字面量以及符号引用,运行时常量池还有一个重要的性质,动态性,要求常量不一定必须是在编译时产生,运行期间也有可能将新的常量放入池中。

直接内存

Java虚拟机自动内存管理机制之内存区域与内存异常