Java虚拟机在Java程序执行的过程中会把其管理的内存分为若干个不同的数据区域。他们有着各自不同的特性。这些区域有的随着虚拟机进程的启动而一直存在,有的和用户线程同生共死。
一、程序计数器
- 程序计数器在内存中是一块比较小的内存空间。它可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令。它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。
- Java中的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的。为了线程切换后能回到正确的位置,每条线程都有其独立的程序计数器,他们之间互不影响,独立存储。
- 如果线程正在执行Java方法,那么计数器记录的是正在执行的字节码指令的地址。如果正在执行的是本地方法,计数器的值应当为空。
- 此内存区域是唯一一个没有规定OutOfMemorryError的区域。
二、Java虚拟机栈
- Java虚拟机栈也是线程私有的,它的生命周期和线程相同。
- 虚拟机栈描述的是Java方法执行的线程内存模型,当每个方法被执行的时候,虚拟机都会同步地创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法入口等信息。每个方法被调用到执行完毕的过程,都对应着栈帧在虚拟机中从入栈到出栈的过程。
- 局部变量表存放了编译器可知的各种Java虚拟机基本数据类型、对象引用、returnAddress类型等。这些数据类型在局部变量表中以局部变量槽来表示。局部变量表的大小在编译期就会被确定。
- 如果线程请求的栈深度大于虚拟机允许的栈深度,将抛出StackOverflowError异常。如果Java虚拟机栈容量可以动态拓展,那在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。
三、本地方法栈
- 其实就是为本地方法服务的栈,功能和上面的Java虚拟机栈一致。
四、Java堆
- Java堆是虚拟机管理的内存中最大的一块,被所有线程共享,在虚拟机启动时创建,它的唯一作用就是创建对象实例。
- Java堆由垃圾收集器管理,由于现代的垃圾收集器都是依据分代理论实现的,所以Java堆中经常会出现“新生代”、”老年代“等名词。但这些仅仅是一部分垃圾收集器的设计风格,而非Java虚拟机实现的固有布局。
- Java堆中可以划分出多个线程私有的分配缓冲区(TLAB),他们可以提升对象分配时的效率。但无论怎样细分,唯一目的都只是更好地更快地分配和管理内存。
- Java堆在物理上可以处于不连续的内存空间中,但在逻辑上应该被视为一致的。但多数虚拟机为了方便一般会将其设计在连续的内存空间当中。