【JVM系列】字节码执行到哪儿了?——说说JVM程序计数器

【JVM系列】字节码执行到哪儿了?------说说JVM程序计数器

欢迎关注,​分享更多原创技术内容~

微信公众号:ByteRaccoon、知乎:一只大狸花啊、稀土掘金:浣熊say

微信公众号海量Java、数字孪生、工业互联网电子书免费送~

什么是程序计数器?

JVM读书的指头------程序计数器

如果我们把字节码文件看作一本书的话,那么JVM的活儿其实很简单。就是照着字节码文件这本书一句一句去读,然后翻译给我们的CPU去执行。所以说JVM也有点儿像一个传达命令的翻译官,将Java源代码文件编译成的字节码文件翻译成各个硬件平台的指令,然后让计算机运行。

那么,不妨想想我们在读书的时候需要干些什么事情,需要有个桌子,草稿纸,书以及人。桌子就好比是计算机内存,Java字节码这本书只能放在内存里,为了提高读书效率,JVM还贴心的将内存分为堆、程序计数器、虚拟机栈、方法区和程序计数器。这些内存区域各有各的作用,但是我们今天重点需要介绍的是------程序计数器。

我们平时读书的时候习惯用手指着书,知道书读到哪一行了,有时候我们可能中途离开干其它事情、读其它书可能会有一个书签,记录当前读到的位置。JVM比我们更聪明一点儿,单独分配了一块儿内存区域叫做程序计数器,来充当手指作用的同时还能在上面记录下当前执行到的JVM 字节码的位置。这样以来在干完其它事的时候,能快速的从上次读过的地方继续开始。

这就是我们说的程序计数器的作用------记录字节码文件的执行位置。

正经说说什么是程序计数器

程序计数器也叫做程序寄存器(Program Counter Register),虽然它在JVM中是一块内存区域,但是其作用更类似于指令寄存器的作用,即会存储JVM需要执行的下一条指令。

在JVM中,程序计数器是线程私有的,每个线程都有自己独立的程序计数器,其生命周期与线程的生命周期保持一致。主要作用包括:

  1. 当前指令地址存储: 程序计数器存储的是当前线程正在执行的Java字节码指令的地址。由于Java是一种解释执行的语言,程序计数器的值被用来定位下一条即将执行的字节码指令。
  2. 线程切换时的恢复点: 程序计数器在线程切换时起到重要作用。当一个线程被挂起,另一个线程被调度执行时,JVM会通过程序计数器来恢复被挂起线程的执行状态,确保程序能够从正确的位置继续执行。
  3. 支持方法调用和返回: 在Java程序中,方法调用和返回都依赖于程序计数器。程序计数器保存方法调用的返回地址,以便方法执行完毕后能够正确返回到调用点。

程序计数器是JVM中唯一一个在多线程执行时不会发生线程安全问题的区域。这是因为每个线程有自己独立的程序计数器,不会被其他线程访问或修改。总体而言,JVM中的程序计数器在支持Java程序的运行时起到了关键的作用,它是实现线程切换和方法调用等功能的重要组成部分。

程序计数器执行流程

如上图所示,当执行Java字节码时,程序计数器(Program Counter,PC)在JVM中起着关键的作用,它负责跟踪当前线程所执行的指令地址。简单来说,程序计数器会存储处于方法区当中Java字节码的指令,表示当前执行到的指令位置。JVM引擎会根据程序计数器的地址拿到指令的物理地址,并从局部变量表和操作数栈中拿到数据进行运算。

这里来尝试分析一段简单的Java代码:

auto 复制代码
public int add(int a, int b) {
    int result = a + b;
    return result;
}

以下是上面Java代码对应的字节码文件以及其在JVM中的执行流程,强调了程序计数器在其中的作用:

java 复制代码
stack=2, locals=4, args_size=3
0: iload_1
1: iload_2
2: iadd
3: istore_3
4: iload_3
5: ireturn
  1. iload_1: 程序计数器记录下将执行的指令的地址偏移0。iload_1指令执行,将局部变量表中索引为1的局部变量(例如,整数变量 a)加载到操作数栈上。
  2. iload_2: 程序计数器更新为下一条指令的地址。iload_2指令执行,将局部变量表中索引为2的局部变量(例如,整数变量 b)加载到操作数栈上。
  3. iadd: 程序计数器继续更新。iadd指令执行,从操作数栈中弹出两个整数,相加并将结果推入操作数栈。
  4. istore_3: 程序计数器继续更新。istore_3指令执行,将操作数栈顶的整数值存储到局部变量表中索引为3的位置(例如,整数变量 result)。
  5. iload_3: 程序计数器再次更新。iload_3指令执行,将局部变量表中索引为3的局部变量的值加载到操作数栈上。
  6. ireturn: 程序计数器继续更新。ireturn指令执行,将结果作为方法的返回值,并结束方法的执行。

在整个执行过程中,程序计数器始终记录着当前线程即将执行的指令的地址。这保证了指令的有序执行,同时在方法调用、返回和异常处理等情况下,程序计数器都发挥了关键的作用。

总结

程序计数器是Java虚拟机(JVM)中的一种寄存器,负责跟踪当前线程执行的字节码指令地址。它在Java程序的执行过程中发挥着关键作用,具体功能包括记录当前指令地址、支持线程切换时的恢复点、以及管理方法调用和返回过程。

在执行Java字节码时,程序计数器通过不断更新指向下一条即将执行的指令地址,保证指令有序地执行。每个线程都有自己独立的程序计数器,确保在多线程执行时不会发生线程安全问题。程序计数器在方法调用、返回和异常处理等情况下都发挥着关键的作用,确保程序能够正确执行。总之,程序计数器是JVM中重要的组成部分,为Java程序的顺利执行提供了必要的支持。

相关推荐
Estar.Lee2 分钟前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
2401_857610032 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
凌冰_2 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞2 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货2 小时前
Rust 的简介
开发语言·后端·rust
monkey_meng3 小时前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
Estar.Lee3 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书4 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放4 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang4 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net