运行时数据区域
JVM在执行JAVA程序的过程中会将由JVM管理的内存区域划分为若干个不同的数据区域。各区域的用途、创建时间和销毁时间不尽相同。
运行时数据区域结构如下图所示
程序计数器
什么是程序计数器?
程序计数器是一个记录着当前线程所执行的字节码的行号指示器。
程序计数器的功能
JAVA程序代码编译后的字节码在即时编译前,其执行方式是通过字节码解释器进行解释执行,而字节码解释器工作时就是通过改变程序计数器的值来轩取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理和线程恢复等基础功能都依赖程序计数器来完成。
为什么需要程序计数器
如果程序只有一个线程,那么不使用程序计数器,让字节码解释器按顺序读取字节码指令并执行,程序完全可以正常运行。但若程序有多个线程,由于JVM的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,同时一个处理器只会执行一条线程,为了保证线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器。
程序计数器的特点
- 占用内存空间小,JVM内存计算时可忽略不计
- 线程私有,各线程间的程序计数器互不影响,独立存储
- 程序计数器是唯一一个没有规定任何OutOfMemoryError情况的内存区域
- 执行navite方法时,程序计数器的值应为空,程序计数器只记正在执行的虚拟机字节码指令的地址
Java虚拟机栈
虚拟机栈也是线程私有的,生命周期与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,JVM都会同步创建一个栈帧用于存储信息,每一个方法从被调用到执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 详见(JVM学习笔记(二)———虚拟机栈)
本地方法栈
- 作用与虚拟机栈非常相似,区别在于虚拟机栈为JAVA方法服务,本地方法栈为本地native方法服务。本地方法栈也是线程私有的内存区域。
- 《Java虚拟机规范》对本地方法栈中方法使用的语言、使用方式与数据结构没有任何强制规定,具体的虚拟机可以根据需要自由实现它。
- 当新的栈帧内存无法分配时JVM将抛出StackOverflowError异常。如果本地方法可以动态扩展,并在扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。
Java堆
- 对于Java应用程序来说,Java堆是虚拟机所管理的最大的内存区域。
- Java堆是被所有线程共享的一块区域,在虚拟机启动时就被创建。
- Java堆的唯一目的就是存放对象实例及数组,几乎所有对象实例都在堆中分配内存(随技术发展已不绝对)。
- Java堆是GC(垃圾收集)的主要区域。
- Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。
- Java堆既可以被实现成固定大小的,也是可以通过参数修改大小实现扩展
方法区
- 方法区也是线程共享的内存区域,在JVM启动时被创建
- 方法区用于存储已经被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码缓存等数据。
- 它的实际的物理内存空间中和Java堆区一样也可以是不连续的。
- 内存区域大小不固定,JVM可以根据应用动态调整,程序开发者也可以指定方法区的初始大小、最小及最大限制。
- 方法区无法满足新的内存分配需求时,将抛出OutOfMemoryError异常。
- 运行时常量池,它是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池表,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到常量池中。运行时常量池受方法区内存限制,当无法申请内存时将抛出OutOfMemoryError异常。
参考书籍 《深入理解Java虚拟机》第三版 ——周志明 本篇内容主要用于作者自身学习总结记录,才疏学浅,如文中出现纰漏,还望指正
|