在学习操作系统、JVM的时都可以看到程序计数器(PC)的身影,但是对于程序计数器的概念一直是模模糊糊,这篇就稍微讲一下什么是PC?

一、JVM层面

什么叫做“程序计数器”?它能做什么?

程序计数器在JMM中的位置如下:

1.1 程序计数器的基本概念

  • 是一个线程私有的数据区域,也就是说,每个线程之间的数据相互不干扰,是一个线程内存空间。

  • 程序计数器 内存空间是不大的,第一眼看到这个名词,很有可能被认为是计量程序执行次数?不不不,千万别这样理解,我们可以把它当做一个下标位置临时存储,例如打断点中的当前断点位置;

  • 对于JVM层面而言,所执行的是class字节码文件,那么字节码文件中的程序逻辑也有顺序。

  • 那么程序计数器中到底存放的是什么内容呢?

    1. 好比下方的一个简单的程序流程图来说,当执行完“用户输入”动作后,下一步的动作是什么?谁知道?只有当前线程的程序计数器知道,"程序计数器"知道,当“输入是否是字符Y”后判断true还是false后,分别执行说明动作?是B操作?C操作?还是其他操作?都需要通过程序计数器来控制。

    2. 换一种描述词,我们还可以把其当做当前线程所执行的字节码的行号指示器。是一种程序控制流的指示器,包括任何的分支、循环、跳转、异常处理、线程恢复等操作都需要依赖于当前线程的程序计数器来指引。

  • 通过程序计数器,将一个个指令,可以连接成一个完整的动作,从而完成整个程序的执行。

1.2 为什么程序计数器的内存空间是私有的呢?

这里就要涉及到多线程环境下的问题了。

  • 在我们的物理机上,可能会存在上百个线程在同时执行,那么每个线程所执行的工作都是不一样的。线程1正在执行开门动作,下一步准备执行关门动作;线程2正在执行扫地动作,下一步准备执行倒垃圾动作;那么两个线程之间的下一步动作都不能相互干扰,不然就乱套了。

  • 在我们的物理机上,会有多核处理器(或者单核处理器),但是只会有一个内核,那么在某一个时刻,只会有一个线程抢占到了内核执行权利。

  • 也就是说,某一个时刻只会执行一个线程所做的事情,那么在多线程环境下,线程间的来回切换是很常见的事情,多线程之间频繁竞争处理器的执行所有权,可能线程1刚执行完开门动作,刚开到一半的门,就被线程2所抢占了,就开始扫地,线程2扫了一下,又被线程1抢占,继续执行开门动作了。

  • 这种频繁的线程唤醒,线程挂起的动作,在每个线程都会高频出现,那么为了保证每个线程在唤起的时候,能够正确的恢复到各自的执行位置,也就是对应的行号指示器的位置,继续执行未完成的动作,那么每个线程都需要有一个独立的程序计数器空间,用于存储各自线程的执行指令控制,保证多线程间相互不影响。这类内存空间也统称为“线程私有”的内存。

1.3 在Java程序 “本地方法(Native Method)”,程序计数器是null?

结合网络大佬的说法,我们也分析一下:

  • 当执行Java程序的时候,我们程序计数器中存的就是Java字节码的地址。

    存放的地址有两种形式:

    (1)相对下一步指令的字节码开始处的偏移量:bytecode index, bci,字节码下标;

    (2)该字节码指令在 JVM内存 中的地址值:bytecode pointer, bcp;

  • 但是对于native method 而言,方法体内容不是由Java程序语言编写的,自然在解释编译阶段,也不能生成对应的字节码数据。

    所以JVM规范上定义了,如果当前执行的方法是本地方法,那么对应计数器所指向的值是未定义的,也就是可能为null。

那么问题来了,如果是null,那么执行了一个本地方法后,接下来要执行什么呢?这如何绑定呢?

  • 这里就是涉及到一个线程映射问题了,我们的 JVM线程是通过映射方式到操作系统上线程执行的。

  • 那么当执行的是一个本地方法的时候,就跳过了映射,直接在系统上执行,并不需要考虑JVM的程序计数器的概念。

  • 那么本地方法执行完成后,就会退出当前栈帧,接着就继续执行后一个方法。是不需要程序计数器提供数据支撑的。本身就是一个操作系统层面的概念了。

二、操作系统层面

程序计数器是什么 PC(program counter)?

在CPU控制部件中的程序计数器(PC)的功能是用于存放指令的地址。程序执行时,PC的初值为程序第一条指令的地址,在顺序执行程序时,控制器首先按程序计数器所指出的指令地址从内存中取出一条指令,然后分析和执行该指令,同时将PC的值加1指向下一条要执行的指令。

2.1 上下文切换

我们都知道系统为了实现并发,操作系统采取了一种高层形式的异常控制流(ECF) 上下文切换,其基本思想就是在程序遇到阻塞,耗时间的系统调用或中断(周期性定时器中断)时CPU会对当前工作线程进行替换,当这些耗时的操作完成时再进行把跳回前面的程序段,这个跳就很有意思了,用户栈,内核栈,状态寄存器等不用说,数据当然该被记录,但操作系统又如何知道代码运行到哪里呢 这就是程序计数器的作用 我们再来看看程序计数器的含义程序计数器(PC)的功能是用于存放指令的地址 这样一想 便清晰了不少

2.2 非本地跳转

非本地跳转是一种用户级的异常控制流 其作用与goto类似 但与goto有一点不同 就是非本地跳转可跨函数进行跳转,其实跳转与上下文切换在某种意义上很相像,他们都要把当前状态转化为另外一种状态,这就牵扯到应该执行到哪一条指令的问题,这也是我们程序计数器的作用

2.3 fork()函数

在 fork 之后父子进行从同一指令开始运行,这是因为子进程拷贝了父进程的程序计数器,而程序计数器的作用是什么,就是存放当前指令 所以就不难理解了。

在三个简单的例子后我们已经大概的理解了程序计数器的作用是什么 接下来我们就来看看程序计数器的处理流程

在程序开始执行前,必须将它的起始地址,即程序的一条指令所在的内存单元地址送入PC,因此程序计数器(PC)的内容即是从内存提取的第一条指令的地址。当执行指令时,CPU将自动修改PC的内容,即每执行一条指令PC增加一个量,这个量等于指令所含的字节数,以便使其保持的总是将要执行的下一条指令的地址。由于大多数指令都是按顺序来执行的,所以修改的过程通常只是简单的对PC加1。

程序计数器是什么(PC)?相关推荐

  1. 程序计数器是什么(PC)

    引言 在学习操作系统的时候很多时候都可以看到程序计数器的身影,但是对于程序计数器的概念一直是模模糊糊,今天算是弄懂了何为PC,遂记录一篇博客. 程序计数器是什么 PC(program counter) ...

  2. ARM 程序计数器 R15(PC)

    寄存器 R15 为程序计数器(PC),它指向 正在取指的地址.可以认为它是一个通用寄存器,但是对于它的使用有许多与指令相关的限制或特殊情况. ARM9 正常操作时,从 R15 读取的值是处理器 正在取 ...

  3. ARM三个寄存器 : 堆栈指针SP(R13)、连接寄存器LR(R14)和程序计数器PC(R15)

    深入理解ARM的这三个寄存器,对编程以及操作系统的移植都是必要的. 1.堆栈指针R13(SP):每一种异常模式都有其自己独立的r13,它通常指向异常模式所专用的堆栈,也就是说五种异常模式.非异常模式( ...

  4. ARM指针寄存器——堆栈指针寄存器SP、程序计数器PC、连接寄存器LR

    参考:堆栈指针寄存器 SP详解以及栈的作用 作者:蓝色鲜橙多 网址:https://blog.csdn.net/qq_36588941/article/details/89873633?utm_sou ...

  5. (转)深入理解SP、LR和PC

    网址:http://blog.csdn.net/zhou1232006/article/details/6149548 深入理解ARM的这三个寄存器,对编程以及操作系统的移植都有很大的裨益. 1.堆栈 ...

  6. Java虚拟机(五)——程序计数器

    文章目录 PC寄存器(程序计数器)概述 PC Register介绍 作用 使用 两个常见问题 为什么使用PC寄存器存储字节码指令地址/为什么使用PC寄存器记录当前线程的执行地址 PC 寄存器为什么被设 ...

  7. 第 4 章 程序计数器

    第 4 章 程序计数器 1.PC 寄存器概述 文档网址 https://docs.oracle.com/javase/specs/jvms/se8/html/index.html PC 寄存器介绍 J ...

  8. 【JVM】运行时数据区介绍,程序计数器和虚拟机栈详解

    JVM越来越是Java面试中的重头戏,今天来总结一下JVM运行时数据区的相关内容. 文章目录 JVM运行时数据区 JVM运行时数据区内部结构 程序计数器(PC寄存器) 程序计数器的介绍 PC寄存器的实 ...

  9. 欧尼酱讲JVM(06)——指点江山—程序计数器

    程序计数器在哪 程序计数器执行过程: 程序计数器(Program Counter Register),也叫PC寄存器,是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器. 在Java ...

最新文章

  1. Occupations(表分割问题)
  2. 等值连接_sql高阶教程:非等值自连接
  3. java外部类调用内部类_java中的外部类和内部类 | 学步园
  4. excel取消隐藏_Excel技巧:批量删除隐藏数据及隐藏工作表
  5. 征战蓝桥 —— 2013年第四届 —— C/C++A组第9题——剪格子
  6. 在SQL Server 2005中解决死锁(转)
  7. 苹果电脑快捷键有哪些?mac系统快捷键大全详细介绍(全部)_苹果MAC_操作系统_脚本之家
  8. 【逻辑与计算理论】Lambda 演算的类型与其 Lambda 演算建模
  9. linux resin 服务功能,linux服务之resin
  10. HTML知识点详细汇总
  11. 「leetcode」98. 验证二叉搜索树:中序遍历【递归】【迭代】详解
  12. 金蝶K3系统与防火墙集成部署方案
  13. 王献之碧玉小楷《洛神赋十三行》王献之小楷高清原石拓本对比图
  14. 如何查看MySQL版本号
  15. 归并排序---------数构
  16. 计算机休眠查询,可不可以查询电脑待机记录
  17. @cacheable 是否缓存成功_你了解缓存吗?缓存在SSD固态中起到什么样的作用?会正确使用吗...
  18. 耶鲁大学公开课:博弈论第九节(笔记)
  19. 最新PHP编写的的技术导航源码 有后台
  20. C语言调用汇编语言(nop)

热门文章

  1. 好家伙,渣男基因被发现了?还能让直男变弯?
  2. VNH7100BASTR资料BTS5090-2EKA驱动器特点R5F562T6DDFF规格参数
  3. 使用NVRAM的简单解决方案
  4. 解读微信内域名防封防拦截的实现方案,随机访问落地页的实现方案
  5. 【总结】开发基于XMPP协议的通讯工具
  6. 你用什么方法做副业赚钱?
  7. XDOJ 171-考勤系统
  8. 10月31今天万圣节,好玩的一天,不信看google首页的图片
  9. Unix/Linux编程:时间转换
  10. retain与remain、sustain与maintain区别