一篇文章带你快速理解 JVM 运行时数据区 、程序计数器详解 (手画详图
[](
)图示:
补充一个点: 在运行时数据区中,灰色的为单独线程私有的,红色的为多个线程共享的,即:
每个线程:独立包括程序计数器、栈、本地栈。
线程间共享:堆、堆外内存(永久代或元空间、代码缓存)
[](
)运行时数据区的完整图:
不同的 JVM 对于内存的划分方式和管理机制存在着部分差异。这里给出一张完整的运行时数据区图。??
看完上面的两张图,我想应该对 JVM 中所谓的运行时数据区有个大概印象了吧。下面??会给大家再给大家带来一些粗略的讲解哈。
[](
)运行时数据区概述:
当我们通过前面的:[类的加载-> 验证 -> 准备 -> 解析 -> 初始化](
) 这几个阶段完成后,就会用到执行引擎对我们的类进行使用,同时执行引擎将会使用到我们运行时数据区 ???♂?
运行时数据区
,Runtime Data Area,用于保存 java 程序运行过程中需要用到的数据和相关信息;经常说的把数据读到内存,包括类加载之后的信息,从磁盘读取文件信息等。即:Java 虚拟机在执行 Java 程序的过程中,会将涉及的数据划分到不同的内存区域去管理。
课间休息会
[](
)二、程序计数器(Program Counter)
[](
)概述:
程序计数器是用于存放下一条指令所在单元的地址的地方。
当执行一条指令时,首先需要根据 PC 中存放的指令地址,将指令由内存取到[指令寄存器](
)中,此过程称为“取指令”。与此同时,PC 中的地址或自动加 1 或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据 PC 取出第二条指令的地址,如此循环,执行每一条指令。
JVM 中的 PC 寄存器是对物理 PC 寄存器的一种抽象模拟。
程序计数器是线程私有内存,是唯一一个在 java 虚拟机规范中没有规定任何 OutOfMemoryError 的区域。
[](
)代码讲解
JAVA 代码编译后的字节码在未经过 JIT(实时编译器)编译前,其执行方式是通过“字节码解释器”进行解释执行。**简单的工作原理为解释器读取装载入内存的字节码,按照顺序读取字节码指令。**读取一个指令后,将该指令“翻译”成固定的操作,并根据这些操作进行分支、循环、跳转等流程。
例如:
使用 javap -c -verbose ClassCode.class 命令反编译出来结果为:
从上面的描述中,可能会产生程序计数器是否是多余的疑问。
因为沿着指令的顺序执行下去,即使是分支跳转这样的流程,跳转到指定的指令处按顺序继续执行是完全能够保证程序的执行顺序的。假设程序永远只有一个线程,这个疑问没有任何问题,也就是说并不需要程序计数器。但实际上程序是通过多个线程协同合作执行的。
首先我们要搞清楚 JVM 的多线程实现方式。JVM 的多线程是通过 CPU 时间片轮转(即线程轮流切换并分配处理器执行时间)算法来实现的。也就是说,某个线程在执行过程中可能会因为时间片耗尽而被挂起,而另一个线程获取到时间片开始执行。当被挂起的线程重新获取到时间片的时候,它要想从被挂起的地方继续执行,就必须知道它上次执行到哪个位置,在 JVM 中,通过程序计数器来记录某个线程的字节码执行位置。因此,**程序计数器是具备线程隔离
的特性,也就是说,每个线程工作时都有属于自己的独立计数器。** 即私有性,每个线程都拥有私有的程序计数器
[](
)使用 PC 寄存器存储字节码指令地址有什么用呢?
其实在上一段文字中已经写了,这里写个缩句哈。
因为 CPU 需要不停的切换各个线程,这时候切换回来以后,就得知道接着从哪开始继续执行。
JVM 的字节码解释器就需要通过改变 PC 寄存器的值来明确下一条应该执行什么样的字节码指令。
评论