憨人笔记之JVM-运行时数据区(程序计数器)

话很少说,干就完了。java

先上图,在以前的文章中,详细介绍了类加载子系统。这里先回顾一下。类加载子系统中的核心部分

  • 类加载过程(类的生命周期)包括加载、链接(验证、准备、解析)、初始化、使用、卸载这么几个过程
  • 系统类加载器,引导类加载器、拓展类加载器、应用类加载器的原理
  • 双亲委派机制的工做原理及实际意义

针对上面的提纲,回想一下是否可以记得每一个类别每一个小点的细节。多线程

本章内容将着重讲述类加载子系统完成类加载以后JVM运行时数据区域。spa

运行时数据区

运行时数据区是虚拟机在执行Java程序的过程成中把所管理的内存划分红不一样的数据区域。每一个区域各司其职,有本身的生命周期,保证程序的稳定运行。有些区域随着虚拟机进程的启动而存在,而有些区域则依赖用户线程的启动和结束而创建和销毁。线程

如上图所示,运行时候数据区主要划分红5大块:程序计数器(Program Counter Register)、虚拟机栈(Java Virtual Machine Stack)、本地方法栈(Native Method Stack)、方法区(Method)、堆(Heap)。按照线程共享的角度上来看,又分为线程共享数据区线程隔离数据区翻译

接下来,详细说说各区域在虚拟机中承担着什么样的角色和做用。设计

程序计数器

程序计数器也被叫作PC寄存器。它是存储指令相关的现场信息,CPU只有把数据装在寄存器中,程序才可以正常执行。程序计数器是一块很小的内存区域,同其余数据区域相比,也是运行速度最快的存储区域3d

它的主要做用就是存储指向下一条指令的地址,也就是将要执行的指令代码,执行引擎会获取它的下一条指令。它就是当前线程所执行的字节码的行号标示。翻译成咱们容易理解的话来说,能够想象成咱们在IDEA中编写代码时候的行号。而执行引擎经过这个行号,能定位到当前行的代码是什么,它将作什么事情。下面用一个伪代码来进行解释:code

1	public class ProgramCounterRegisterTest {
2    		public static void main(String[] args){
3        		int i = 1;
4        		System.out.println("打印变量i的值:" + i);
5    		}
6	}
// 例如行号为3, 它将进行为变量i赋值为1的操做。这里行号3就能够看做成PC寄存器中指令的地址,int i = 1 能够看做要执行的指令
复制代码

经过javap对这个类的class字节码文件进行反编译,来看看在字节码文件中,什么表示指令地址:cdn

当执行引擎在执行指令的时候,就会从PC寄存器中经过指令地址"0"找到其对应的指令为iconst_1而后再进行指令的执行(后面对字节码文件会有详细的介绍)。blog

程序计数器做为运行时数据区的重要组成部分,具备一下特色:

  • 线程私有,每个线程都会有本身独立的程序计数器,各线程之间互不干扰,生命周期伴同线程的生命周期一致
  • 若是执行的是Java方法,会保存虚拟机正在执行的字节码文件的指令地址,若是执行的是Native方法,计数器的值为空(undifined)
  • 程序的控制流指示器,分支、循环、跳转、异常处理、线程恢复等功能都依赖它来完成
  • 是整个虚拟机运行时数据区惟一不会发生OutOfMemoryError的内存区域。
程序计数器存储的字节码指令地址有何做用?为何要记录当前线程的执行地址?

现入现在的程序都会存在多线程的状况,可是CPU一次只能执行一个线程,CPU经过时间片来控制线程的切换,时间片的时间很小,使得感受是在多个线程在同时执行。因此,如何保证程序在多线程在线程切换的过程当中,可以还原到线程上次执行的代码呢,就是经过程序计数器。

因为程序计数器是线程私有的,对于一个线程来讲,字节码解释器会经过改变程序计数器中的指令地址来明确下一条应该执行什么指令,而在多线程的状况下,在线程切换的时候,可以保证切换回来的线程可以在以前的基础上继续执行,从而保证程序的正常运行。以上,就是程序计数器是必不可少的也是要设计成线程私有的缘由。

程序计数器相对来讲在整个运行时数据区属于比较简单的数据区域。主要就是如上图的几点内容。


不怕路歹行不怕大雨淋,心上一字敢 面对个人梦,甘愿来做憨人。 --<憨人>

相关文章
相关标签/搜索