1.运行时数据区图


运行时数据区是在类加载完成后所经历的阶段,当我们通过前面的:类的加载 --> 验证 --> 准备 --> 解析 --> 初始化,这几个阶段完成后,执行引擎就会对类进行使用,这时就用到了运行时数据区。

举例来说,类的加载过程就好像是买菜的过程,经过一系列奔波,从购买到检验,最后再送到厨房(也就是运行时数据区)。而执行引擎就是一名厨师,他会用准备好的蔬菜去进行菜品的制作。

2.程序计数器(PC寄存器)

官方文档网址:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

2.1 PC寄存器介绍

  • JVM中的程序计数寄存器(Program Counter Register)中,Register的命名源于CPU的寄存器,寄存器存储指令相关的现场信息。CPU只有把数据装载到寄存器才能够运行。
  • 这里,并非是广义上所指的物理寄存器,或许将其翻译为PC计数器(或指令计数器)会更加贴切(也称为程序钩子),并且也不容易引起一些不必要的误会。JVM中的PC寄存器是对物理PC寄存器的一种抽象模拟。
  • 它是一块很小的内存空间,几乎可以忽略不记。也是运行速度最快的存储区域。
  • 在JVM规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致。
  • 任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址;或者,如果是在执行native方法,则是未指定值(undefned)。
  • 它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
  • 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
  • 它是唯一一个在Java虚拟机规范中没有规定任何OutofMemoryError情况的区域。

2.2 PC寄存器的作用

PC寄存器用来存储指向下一条指令的地址,也即将要执行的指令代码。由执行引擎读取下一条指令,并执行该指令。

 static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=3, locals=0, args_size=0
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: invokestatic #5 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
13: invokevirtual #6 // Method java/lang/Thread.getName:()Ljava/lang/String;
16: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #8 // String 初始化当前类
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: goto 30
LineNumberTable:
line 22: 0
line 23: 30
StackMapTable: number_of_entries = 1
frame_type = 30 /* same */
}

上面字节码中左边的数字代表指令地址(指令偏移),即 PC 寄存器中可能存储的值,然后执行引擎读取 PC 寄存器中的值,并执行该指令,中间的就是指令,后面的#+数字则是运行时常量池中的符号引用,具体后面会说。

面试题

1.使用PC寄存器存储字节码指令地址有什么用呢?

  • 因为CPU需要不停的切换各个线程,这时候切换回来以后,就得知道接着从哪开始继续执行
  • JVM的字节码解释器就需要通过改变PC寄存器的值来明确下一条应该执行什么样的字节码指令

2.PC寄存器为什么被设定为私有的?

  • 我们都知道所谓的多线程在一个特定的时间段内只会执行其中某一个线程的方法,CPU会不停地做任务切换,这样必然导致经常中断或恢复,如何保证分毫无差呢?为了能够准确地记录各个线程正在执行的当前字节码指令地址,最好的办法自然是为每一个线程都分配一个PC寄存器,这样一来各个线程之间便可以进行独立计算,从而不会出现相互干扰的情况。
  • 由于CPU时间片轮限制,众多线程在并发执行过程中,任何一个确定的时刻,一个处理器或者多核处理器中的一个内核,只会执行某个线程中的一条指令。
  • 这样必然导致经常中断或恢复,如何保证分毫无差呢?每个线程在创建后,都会产生自己的程序计数器和栈帧,程序计数器在各个线程之间互不影响。

扩展:

CPU 时间片

  • CPU时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片。
  • 在宏观上:我们可以同时打开多个应用程序,每个程序并行不悖,同时运行。
  • 但在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,如何处理公平,一种方法就是引入时间片,每个程序轮流执行。

并行,并发

  • 并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。
  • 而并发是指两个或多个任务在同一时间间隔执行(线程来回切换)。

JVM-运行时数据区之PC寄存器的更多相关文章

  1. Java内存管理:Java内存区域 JVM运行时数据区

    转自:https://blog.csdn.net/tjiyu/article/details/53915869 下面我们详细了解Java内存区域:先说明JVM规范定义的JVM运行时分配的数据区有哪些, ...

  2. JVM运行时数据区和垃圾回收机制

    最近参考各种资料,尤其是<深入理解Java虚拟机 JVM高级特性和最佳实践>,大牛之作.把最近学习的Java虚拟机组成和垃圾回收机制总结一下. 你不会的都是新知识,学无止境,每天进步一点点 ...

  3. Java中的字符串常量池和JVM运行时数据区的相关概念

    什么是字符串常量池 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量 ...

  4. Jvm运行时数据区

    一:运行时数据区 Java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域.这些区域有着各自的用途,一级创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户 ...

  5. JVM 运行时数据区 (三)

    JVM运行时数据区 运行时数据区由 程序计数器.java虚拟机栈.本地方法栈.堆.方法区 组成: 1.程序计数器 每一个Java线程都有一个程序计数器,用于保存程序执行到当前方法的哪一个指令,它是线程 ...

  6. JVM总结(一):概述--JVM运行时数据区

    大三下,趁着寒假重温一遍JVM,准备在一个系列来总价一下学习JVM的整个过程.争取在接下来的一个星期内更新完这一个系列,然后回家过年. JVM运行时数据区 线程私有的数据区 程序计数器 虚拟机栈 本地 ...

  7. JVM运行时数据区与JVM堆内存模型小结

    前提 JVM运行时数据区和JVM内存模型是两回事,JVM内存模型指的是JVM堆内存模型. 那JVM运行时数据区又是什么? 它包括:程序计数器.虚拟机栈.本地方法栈.方法区.堆. 来看看它们都是干嘛的 ...

  8. Jvm运行时数据区 —— Java虚拟机结构小记

    关于jvm虚拟机的文章网上都讲烂了.尤其是jvm运行时数据区的内容. 抱着眼见为实的想法,自己翻了翻JVM规范,花了点时间稍微梳理了一下. 以下是阅读Java虚拟机规范(Java SE 8版)的第二章 ...

  9. JVM运行时数据区及对象在内存中初始化的过程

    JVM运行时数据区 Java虚拟机所管理的内存区域,也称为运行时数据区,分为以下几个运行时数据区,如图所示 程序计数器:当前程序所执行字节码的行号指示器 程序计数器(Program Counter R ...

  10. JVM 运行时数据区(二)

    @ 目录 运行时数据区 共享区 堆区 方法区 隔离区 虚拟机栈 栈帧 本地方法栈 程序计数器 运行时数据区 JVM 运行时数据区主要分为5块 方法区 JDK1.8以后叫做元数据区(Metaspace) ...

随机推荐

  1. Day07_37_深度剖析集合中的contains()方法

    深度剖析集合中的 contains()方法 contains()方法查找集合中是否包含某个元素 contains() 底层使用的是 equals()方法 当contains()方法拿到一个对象的时候, ...

  2. Appium 简介与自动化测试环境搭建

    1. Appium 简介 2. Appium 自动化测试环境搭建 1. Appium 简介 Appium 是一个开源测试自动化框架,可用于原生,混合和移动 Web 应用程序测试. 它使用 WebDri ...

  3. k8s 安装 rabbitMQ 单机版

    rabbitMQ docker镜像使用rabbitmq:3.8-management service.yaml文件 apiVersion: v1 kind: Service metadata: nam ...

  4. ambari介绍及安装

    Ambari简介 Ambari概述 Apache Ambari是一种基于Web的工具,支持Apache Hadoop集群的创建.管理和监控.Ambari已支持大多数Hadoop组件,包括HDFS.Ma ...

  5. JPA简单的分页条件查询

    1,service层代码: @Override public QrCodeRecordPaging getPage(String projectId, Integer pageNumber, Inte ...

  6. PAT归纳总结——关于模拟类问题的一些总结

    关于时间的模拟问题 在刷题的过程中碰到了一些关于时间先后顺序的模拟题目,刚开始做的时候确实挺麻烦的,今天把这类问题的解题思路来整理一下. 比较典型的有: 1017 Queueing at Bank 1 ...

  7. 07- Linux常用命令

    cat命令 作用:将文件内容作为标准输出打印到终端. 格式:cat   文件名1  文件名2 例如: cat more命令: 作用:分页显示文本文件的内容 格式:more 文件名 实例:more he ...

  8. js收藏展开与隐藏,返回顶部

    var a = document.getElementById("more");var b = document.getElementById("moreList&quo ...

  9. adbi学习:java hook实现机制

    adbi的java hook实现代码ddi不在之前下载的文件中,下载地址:https://github.com/crmulliner/ddi,具体的编译看readme里面很详细的介绍了.注意ddi代码 ...

  10. Python中的BeautifulSoup模块

    目录 BeautifulSoup Tag NavigableString BeautifulSoup Comment 遍历文档树 直接子节点 所有子孙节点 ​ 节点内容 搜索标签 CSS选择器 Bea ...