1.运行时数据区
首先参考这张图片,我们可以清楚地看出常说的堆、栈都处于运行时数据区。同时堆和方法区是线程共享的,而程序计数器(PCR)和栈是线程私有的。
1.1程序计数器
Program Counter Register是当前线程所执行的字节码的行号指示器。每条线程都有一个独立的PCR,彼此之间互不影响。
如果程序执行的是java方法,则计数器值为当前字节码指令地址,如果执行的是native方法,则计数器为空。
程序计数器这部分内存空间是唯一一个不会出现OutOfMemoryError的区域。
1.2虚拟机栈
Java Virtual Machine Stacks的生命周期与线程相同,为线程私有。
局部变量表存放在栈中,其所需要的内存空间在编译器就会完成分配。
- 局部变量表
- 基本数据类型(boolean,byte,char,short,int,float,long,double)
- 对象引用(reference)
- returnAddress(指向了一条字节码指令的地址)
这个区域可能对应两种异常:
- 两种异常:
- StackOverflowError:如果虚拟机栈不允许动态扩展,且线程请求的栈深度大于虚拟机允许的最大深度时触发。
- OutOfMemoryEroor:如果虚拟机栈可以动态扩展,但是扩展时无法申请到足够的内存时触发。
1.3堆
Heap是内存中最大的一块,被所有线程所共享,唯一的用处就是存放对象实例。
堆也被称为GC堆(Garbage Collected Heap),因为它是垃圾收集器管理的主要区域。从内存回收的角度可以将堆分为新生代和老生代,再细致为Eden,From Survivor和To Survivor.
堆可以处于不连续的内存空间。如果堆中没有内存完成实例分配且堆再也无法拓展时,抛出OutOfMemoryError异常。
1.4方法区
Method Area是线程共享的区域,垃圾回收在这个区域很少出现。它用于存放已经被虚拟机加载的类信息、常量、静态变量和编译器编译后的代码等数据。
方法区不需要连续的内存,也不一定有固定的大小,可以拓展。当方法区无法满足内存分配的需求时,抛出OutOfMemoryError异常。
1.4.1运行时常量
Runtime Constant Pool是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。
1.5直接内存
Direct Memory不属于运行时数据区,甚至不属于虚拟机中的内存取悦。它是利用通道和缓冲区的I/O方式,使用native函数库分配堆外内存,然后通过堆中的DirectByteBuffer对象作为这块内存的引用进行操作。
把直接内存放这里一起记录,是因为它还是会收到本机内存的限制,从而导致动态拓展时可能抛出OutOfMemoryError.