JVM介绍及结构
1. 什么是JVM?
JVM指的是Java虚拟机,本质上是一个运行在计算机上的程序,负责运行Java字节码文件。充当一个适配器的角色,以实现Java跨平台的特性。
1.1 JVM的功能
- 解释执行字节码指令
- 管理内存中对象的分配,完成自动的垃圾回收
- 优化热点代码以提升效率(JIT)
1.2 JVM的组成
总体分为,类加载子系统、运行时数据区、执行引擎、本地方法接口四部分。如图:

2. 运行时数据区组成
运行时数据区指的是JVM所管理的内存区域。按照是否线程共享分类,分为两类:
- 线程共享: 方法区、堆
- 线程不共享: 本地方法栈、虚拟机栈、程序计数器
如下图所示:

2.1 程序计数器(Program Counter Register)
也叫PC寄存器,每个线程通过PC来记录当前要执行的字节码地址。主要作用有两个:
- 用于控制程序指令的进行,实现分支、跳转、异常等逻辑;
- 多线程下,JVM通过PC记录线程切换钱执行到哪一句指令,并继续解释执行。
2.2 虚拟机栈
数据结构如其名,采用栈结构来管理方法调用中的基本数据,每个方法调用采用一个栈帧来保存。每个线程都会包含自己的虚拟机栈。因此,生命周期和其所属的线程相同。
其中,栈帧包含以下几个部分:
- 局部变量表,即在方法执行过程中所存放的局部变量;
- 操作数栈,JVM在执行指令过程中用来存放临时数据的区域;
- 帧数据,包含动态链接、方法出口、异常表等内容。
备注:
- 动态链接: 方法中要用到其他类的属性和方法,这些内容在字节码中以编号保存,运行过程中会将其替换成内存中的地址。这个编号到内存的映射关系就保存在动态链接中。
- 方法出口:方法调用完需要弹出栈帧,回到上一个方法,朝旭计数器切换到上一个方法地址继续进行,方法出口保存的就是这个地址;
- 异常表:存放的时代码中的异常处理信息,包含异常捕获的生肖范围以及异常发生后的跳转的字节码指令位置。
2.3 本地方法栈
^fad115
本地方法栈是用于存储调用Native本地方法的栈帧。在Hotspot虚拟机中,虚拟机栈和本地方法栈使用的是同一块栈空间。本地方法会在占内存上生成一个栈帧,用于临时保存方法的参数,同时也方便出现异常时能够把本地方法栈信息也打印出来。
2.4 堆(Heap)
堆位JVM中空间最大的一块内存区域,创建出来的对象都存在堆上,且线程共享。因此堆也是垃圾回收的重点区域。
栈上的局部变量表中,可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通过静态变量可以实现对象在线程之间的共享。
2.5 方法区
方法区作用时存放一些基础信息,包括:
- 每个加载的累的原信息(基础信息);
- 运行时常量池,保存字节码文件中的常量池内容,避免重复创建,减少内存的开销;
- 字符串常量池,存储字符串常量。
方法区市Java虚拟机规范提出的一个概念,在HotSpot不同版本中会用永久带或者元空间来实现。
关于字符串常量池:
- JDK1.7之前,运行时常量池(字符串常量池也在里边)是存放在方法区,此时方法区的实现是永久带。
- JDK1.7字符串常量池被单独从方法区移到堆中,运行时常量池剩下的还在永久带(方法区)
- JDK1.8,永久带更名为元空间(方法区的新的实现),但字符串常量池池还在堆中,运行时常量池在元空间(方法区)。
2.6 直接内存
直接内存有操作系统直接管理,不属于Java运行时内存区域。是在JDK1.4之后,引入的NIO机制使用,主要是为了提升读写数据性能。
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.