程序计数器只记录当前线程下一条要执行的字节码指令地址(或偏移量),由JVM自动更新:初始指向入口方法首指令,顺序执行时递增,分支跳转时直接写入目标地址,线程切换时保存恢复,执行native方法时值为undefined。

Java 中程序计数器(Program Counter Register,简称 PC 寄存器)不记录“源代码行号”,也不保存方法名或变量名,它只记录当前线程下一条要执行的字节码指令的内存地址(或偏移量)。这个过程完全由 JVM 自动完成,开发者无法读取、设置或干预。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
程序计数器如何记录执行地址
- JVM 在类加载阶段把
.class文件中的字节码指令加载进内存,并为每条指令分配一个连续的地址(或基于起始位置的偏移量) - 每个线程启动时,JVM 为其分配独立的程序计数器,初始值设为该线程入口方法(如
main())第一条字节码指令的地址 - 执行引擎每执行完一条字节码指令,就根据该指令长度自动更新程序计数器,使其指向下一条指令地址;多数情况下就是简单地“+1”(按字节码单位偏移)
- 遇到分支(如
if_icmpne)、跳转(如goto)、循环(如goto回退)、异常处理(athrow后跳转到 handler)时,JVM 直接把目标指令地址写入程序计数器,从而改变执行流向
线程切换时怎么保持地址正确
- 线程被挂起前,JVM 会把它的程序计数器当前值(即“下一条要执行的地址”)保存在该线程的私有栈帧或调度上下文中
- 当该线程恢复执行时,JVM 把之前保存的地址重新载入其程序计数器,接着从那里继续执行
- 因为每个线程都有自己的程序计数器,所以多个线程交替执行不会互相覆盖执行位置
native 方法的情况
- 如果当前线程正在执行 native 方法(如
Object.wait()、System.currentTimeMillis()),程序计数器的值被设为undefined - 这是因为控制权已交给本地库,JVM 不再解释字节码,也无法追踪本地代码的指令地址
补充说明
- 程序计数器存储的是 JVM 层面的字节码地址,不是操作系统机器码地址;但在 JIT 编译后,实际执行可能走本地代码,此时 PC 值在 dump 中显示为本地内存地址(如
pc=0x0000000123456789),但这对 Java 层不可见、不可控 - 它是唯一一个在 JVM 规范中明确声明不会发生
OutOfMemoryError的运行时内存区域,因为只存一个固定长度的地址(32 位系统占 4 字节,64 位系统占 8 字节)
不复杂但容易忽略

















