文章目录
一、概述
Java虚拟机在执行Java程序过程中会把它所管理的内存划分为若干个不同的数据区域。
Java虚拟机运行时数据区如下图所示:
从上图可知,Java虚拟机运行时数据区可分为6部分:
- 方法区
- 堆
- 虚拟机栈
- 本地方法栈
- 程序计数器
- 直接内存
按照内存是否线程共享的维度,可将上面6个区域进行分类:
- 线程共享的数据区:
方法区(包含 运行时常量区)
、堆
- 线程私有的数据区:
虚拟机栈
、本地方法栈
、程序计数器
- 其他:
直接内存
关联文章:
- 《JVM(一) — Class 文件结构》
- 《JVM(二) — 字节码指令》
- 《JVM(三) — Java虚拟机运行时内存结构》
- 《JVM(四) — 垃圾回收机制》
- 《JVM(五) — 类加载机制》
- 《JVM(六) — JVM面试问题》
- 《JVM — 字节码文件分析》
下面对每一个运行时数据区进行讲解。
二、运行时数据区
2.1 程序计数器
线程私有的,其内存空间占用较小,可以看成是当前线程所执行的字节码的行号指示器。字节码解析器工作时就是通过改变这个计数器的值来选取吓一跳需要指向的字节码指令。
说明:
- 如果正在指向的是Java方法,则这个计数器记录的是正在执行的虚拟机字节码指令的地址。
- 如果正在执行的是Native方法,则这个计数器的值为空。
2.2 Java虚拟机栈
描述的是Java方法执行的内存模型,特点如下:
- 线程私有的,其生命周期与线程相同。
- 每个方法在执行的同时都会创建一个栈帧用于存放局部变量表、操作数栈、动态链接、方法出口等信息。
- 每个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
说明:
通常人们将Java内存区分为堆内存和栈内存(不严谨的分法),其中堆内存对应上图的堆(Heap)部分,栈内存对应虚拟机栈(或者虚拟机栈中的局部变量表部分)。
2.3 本地方法栈
本地方法栈
与 虚拟机栈
类似,也是线程私有的。
区别:
本地方法栈
:为虚拟机执行Native方法服务;虚拟机栈
:为虚拟机执行Java方法服务;
2.4 Java堆 (Heap)
Java堆的特点:
- Java堆是虚拟机中最大的一块内存。
- Java堆在虚拟机启动时被创建;作用就是存放对象实例。
- Java堆是垃圾收集器管理的主要区域,因此也叫
GC堆
。 - 从内存回收角度看,由于目前收集器基本采用分代收集算法,因此Java堆可以细分为:新生代、老年代。
- 从内存分配角度看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区(TLAB)。
- 上述两点对Java堆的细分都是为了更快的分配内存,更好的回收内存。
2.5 方法区
方法区的特点:
- 内存区域线程共享。
- 用于存储已被虚拟机加载的
类信息
、常量
、静态变量
、即时编译器编译后的代码
等数据。 - 方法区的内存可以不实现垃圾回收,即使要回收,也主要是针对常量池和对类型的卸载;
2.6 运行时常量池
运行时常量池特点:
- 运行时常量池是方法区的一部分。
- ClassFile 结构中有一项信息是常量池,这部分内容将在类被加载后进入方法区的运行时常量池中。
2.7 直接内存
直接内存的特点:
- 不属于虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。
- 直接内存的分配不会受到Java堆大小的影响,但受到本机总内存的限制。
- 在配置虚拟机参数时,不要忽略直接内存,防止出现OutOfMemoryError异常
三、对象的创建
根据《JVM(二) — 字节码指令》 可知,创建一个对象对使用字节码指令 new
,而构建一个对象的过程如下所示。
对象的创建过程:
- 虚拟机接收到一条
new
指令,首先会检查这个指令的参数是否可以在常量池中定位到一个类的符号引用。 - 当定位到符号引用后,会校验这个符号引用代表的类是否被加载过,如果类没有加载过,则执行第3步,否则执行第4步。
- 类没有被加载过,则指向类加载流程。
- 类被加载过之后,虚拟机会向新生对象分配内存(对象所需内存大小在类加载完成后便可确定),即从对内存中划分一部分内存给新对象。
- 内存分配结束后,虚拟机需要将分配到的内存空间都初始化为零值,这步操作保证对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
- 执行完第5步后,从虚拟机角度看新对象已经产生,但从Java程序角度看,对象才刚刚创建,
<init>
方法都没有执行,因此执行完new指令
之后会接着执行invokespecial <init>
方法(构造方法),此时对象才算创建完成。 - 将对象引用入栈,即将对象的引用赋值给变量,存入局部变量表(虚拟机栈)中。
参考
- 《深入理解Java虚拟机》
- 《JVM(一) — Class 文件结构》
- 《JVM(二) — 字节码指令》