JVM_程序计数器详解
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域。
1、内存管理
2 、运行时数据区域内容
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域。
3、程序计数器
3.1 主要内容
程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。
在Java虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地(Native)方法,这个计数器值则应为空(Undefined)。此内存区域是唯一一个在《Java虚拟机规范》中没有规定任何OutOfMemoryError情况的区域。
3.2 程序计数器详解
简介
(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。(概念模型中:字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令)
线程私有:多线程是通过线程轮流切换并分配处理器执行时间的方式实现的。为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
状态:
①执行java方法,计数器记录虚拟机字节码指令的地址;
②执行native方法,计数器为空(undefined)
唯一一个再java虚拟机规范中没有规定任何OutOfMemoryError的区域。
特点及分析
①占用内存小,唯一不会OutOfMemoryError的区域(在编译时已经确定该线程代码的偏移量最大值,根据该最大偏移量可以分配内存空间:A字节;或者JVM已确定程序计数器的大小:X字节。不管是A字节还是X字节,都已经保证程序计数器的最大偏移量≤空间最大值。另外,在线程运行时,只改变程序计数器的值,不涉及空间的扩展,所以不会存在空间不够用的情况)
②线程私有(因为JVM里多线程运行时,(最少也会有main, gc),是通过轮流切换并分配处理器执行时间的方式运行的,在确定的某一时刻,一个CPU(或内核)只有一个线程运行(一个线程中的程序计数器改变),需要保证线程切换后能恢复到正确的执行位置——每条线程一个程序计数器,彼此独立,互不干扰)
③对java方法是字节码偏移量,对于native方法是undefined(native是非java代码编写的,比如C,C++, 它们无法在java编译时生成字节码,即JVM获取不到native实现,只能通过系统指令去调用native方法)
Java线程总是需要以某种形式映射到OS线程上。映射模型可以是1:1(原生线程模型)、n:1(绿色线程 / 用户态线程模型)、m:n(混合模型)。以HotSpot VM的实现为例,它目前在大多数平台上都使用1:1模型,也就是每个Java线程都直接映射到一个OS线程上执行。此时,native方法就由原生平台直接执行,并不需要理会抽象的JVM层面上的“pc寄存器”概念——原生的CPU上真正的PC寄存器是怎样就是怎样。就像一个用C或C++写的多线程程序,它在线程切换的时候是怎样的,Java的native方法也就是怎样的。
执行native本地方法时,程序计数器的值为空(Undefined)。因为native方法是java通过JNI直接调用本地C/C++库,可以近似的认为native方法相当于C/C++暴露给java的一个接口,java通过调用这个接口从而调用到C/C++方法。由于该方法是通过C/C++而不是java进行实现。那么自然无法产生相应的字节码,并且C/C++执行时的内存分配是由自己语言决定的,而不是由JVM决定的。
更多推荐
所有评论(0)