Appearance
程序计数器
程序计数器是线程私有的小块内存,用来记录当前线程正在执行的字节码指令位置。它很少直接导致线上故障,但对理解线程切换、字节码执行和异常栈很重要。
作用
Java 线程执行字节码时,程序计数器保存当前指令位置。线程被 CPU 切走再切回来时,JVM 需要知道从哪里继续执行。
text
线程 A -> 执行到指令 15 -> 被切走
线程 B -> 执行
线程 A -> 恢复到指令 15 继续执行特点
| 项目 | 说明 |
|---|---|
| 线程关系 | 每个线程独立拥有 |
| 生命周期 | 随线程创建和销毁 |
| 存储内容 | 当前字节码指令地址或执行位置 |
| 常见异常 | 规范中没有规定该区域 OOM |
| 对 native 方法 | 执行 native 方法时值可能为空或未定义 |
和栈的关系
程序计数器记录“执行到哪里”,虚拟机栈记录“方法调用现场”。两者配合让线程可以暂停、恢复和继续执行。
| 区域 | 关注点 |
|---|---|
| 程序计数器 | 当前执行指令位置 |
| 虚拟机栈 | 当前调用链和每个方法的栈帧 |
为什么需要了解它
理解多线程
多线程不是每个线程一直占着 CPU。线程会频繁切换,程序计数器帮助 JVM 恢复每个线程自己的执行位置。
理解字节码
查看字节码:
bash
javap -c Demo输出中的偏移量可以理解为指令位置。程序计数器保存的就是类似位置。
理解异常栈
异常栈展示方法调用链,程序计数器和栈帧共同帮助 JVM 定位执行现场。
排查价值
程序计数器很少是问题根因,但它能帮助理解:
- 为什么线程切换后还能继续执行。
- 为什么每个线程有独立调用栈。
- 字节码跳转、循环、异常处理如何定位。
遇到实际问题时,通常看的是线程栈:
bash
jstack <pid>
jcmd <pid> Thread.print程序计数器作为底层概念理解即可,不需要单独调参。
