目录
1、JVM虚拟机学习系列之一(Java虚拟机的发展史和java发展重大事件)
2、JVM虚拟机学习系列之二(Java虚拟机的内部结构、整体框架、类加载子系统、双亲委派机制)
3、JVM虚拟机学习系列之三(Java虚拟机的运行时数据区:程序计数器+虚拟机栈+局部变量表)
4、JVM虚拟机学习系列之四(Java虚拟机的字节码与类的加载)
5、JVM虚
前言
学习完本章,你会学到什么是Java虚拟机的运行时数据区、程序计数器、虚拟机栈、局部变量表等。
一、虚拟栈的位置结构图
二、什么是运行时数据区?
1、Java虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有--些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与线程一一对应的,这些与线程对应的数据区域会随着线程开始和结束而创建和销毁。
2、上图中红色右边的为单独线程私有的,红色的为多个线程共享的。即:
➢每个线程:独立包括程序计数器、栈、本地栈。
➢线程间共享:堆、堆外内存(有的人也叫他永久代或元空间、代码缓存)
3、Hotspot java虚拟机的后台线程如下:
➢虚拟机线程:这种线程的操作是需要JVM达到安全点才会出现。这些操作必须在不同的线程中发生的原因是他们都需要JVM达到安全点,这样堆才不会变化。这种线程的执行类型包括” stop-the-world"的垃圾收集,线程栈收集,线程挂起以及偏向锁撤销。
➢周期任务线程:这种线程是时间周期事件的体现(比如中断),他们一般用于周期性操作的调度执行。
➢GC线程:这种线程对在JVM里不同种类的垃圾收集行为提供了支持。
➢编译线程:这种线程在运行时会将字节码编译成到本地代码。
➢信号调度线程:这种线程接收信号并发送给JVM,在它内部通过调用适当的方法进行处理。
三、程序计数器(PC寄存器)指什么
1、JVM中的程序计数寄存器(Program Counter Register) 中,Register 的命名源于CPU的寄存器,寄存器存储指令相关的现场信息。CPU只有把数据装载到寄存器才能够运行。
2、这里的寄存器并不是指的物理寄存器,JVM中的PC寄存器是对物理PC寄存器的一种抽象模拟。寄存器我们通常也叫PC计数器(或指令计数器)、或叫程序钩子。
PC寄存器器介绍
1、它是一块很小的内存空间,几乎可以忽略不记。他也是运行速度最快的存储区域。
2、在JVM规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致。
3、任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址;或者,如果是在执行native方法,则是未指定值(undefned)。
4、它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础字节码解释器工作时就是通过改变这个计数器的值来选取下--条需要执行的字节码指令。
5、它是唯一一个在Java 虚拟机规范中没有规定任何OutOtMemoryError情况的区域。
四、虚拟机栈的理解
1、虚拟机栈概述
a、由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。
b、优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。
2、虚拟机内存中的栈与堆
a、栈是运行时的单位,而堆是存储的单位。即:栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。堆解决的只是数据存储的问题,即数据怎么放、放在哪儿。也可以理解成栈管运行,堆管存储。
b、方法区有时可以使用本地内存。堆空间在内存中相当于最大的。
3、虚拟机栈基本内容
●Java虚拟机栈是什么?
1、Java虚拟机栈(Java Virtual_ Machine Stack) ,早期也叫Java栈。每个线程在创建时都会创建一个虚似机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次的Java方法调用。
2、虚拟机栈也是线程私有的。
●生命周期:生命周期和线程一致。
●作用:主管Java程序的运行,它保存方法的局部变量、部分结果,并参与方法的调用和返回。
1、局部变量 vs 成员变量(属性)
2、基本数据变量 vs 引用数据类型(类、数组、对象)
●栈的特点:
1、栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器。
2、JVM直接对Java栈的操作只有两个,➢每个方法执行,伴随着进栈(入栈、压栈)➢执行结束后的出栈工作
3、对于栈来说不存在垃圾回收问题
4、Java虚拟机规范允许Java栈的大小是动态的或者是固定不变的。
●设置栈内存大小:我们可以使用参数-Xss选项来设置线程的最大栈空间,栈的大小直接决定了函数调用的最大可达深度。
官方文档设置栈大小的地址:https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE
4、虚拟机栈运行原理
a、JVM直接对Java栈的操作只有两个,就是对栈帧的压栈和出栈,遵循“先进后出”/“后进先出”原则。
b、在一条活动线程中,-一个时间点上,只会有一个活动的栈帧。即只有当前正在执行的方法的栈帧(栈顶栈帧)是有效的,这个栈帧被称为当前栈帧(Current Frame) ,与当前栈帧相对应的方法就是当前方法(Current。Method),定义这个方法的类就是当前类(Current Class)
c、执行引擎运行的所有字节码指令只针对当前栈帧进行操作。
d、如果在该方法中调用了其他方法,对应的新的栈帧会被创建出来,放在栈的顶端,成为新的当前帧。
5、局部变量表(Iocal variables)
a、局部变量表也被称之为局部变量数组或本地变量表。
b、定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,.这些数据类型包括各类基本数据类型、对象引用(reference),以及returnAddress类型。
c、由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题。
c、局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的Code属性的maximum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的。
e、方法嵌套调用的次数由栈的大小决定。一般来说,栈越大,方法嵌套调用次数越多。对一个函数而言,它的参数和局部变量越多,使得局部变量表膨胀,它的栈帧就越大,以满足方法调用所需传递的信息增大的需求。进而函数调用就会占用更多的栈空间,导致其嵌套调用次数就会减少。
f、局部变量表中的变量只在当前方法调用中有效。在方法执行时,虚拟机通过使用局部变量表完成参数值到参数变量列表的传递过程。当方法调用结束后,随着方法栈帧的销毁,局部变量表也会随之销毁。.
关于Slot的理解
参数值的存放总是在局部变量数组的index0开始,到数组长度-1的索引结束。
●局部变量表。最基本的存储单元是Slot (变量槽)
●局部变量表中存放编译期可知的各种基本数据类型(8种),引用类型(reference),returnAddress类型的变量。
●在局部变量表里,32位以内的类型只占用一个slot (包括returnAddress类型),64位的类型(long和double)占用两个slot。
➢byte、short、charr在存储前被转换为int,boolean 也被转换为int,0表示false,非0表示true。
➢long 和double 则占据两个Slot。
● JVM会为局部变量表中的每一个slot都分配一个访的索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值。
● 当一个实例方法被调用的时候,它的方法参数和方法体内部定义的局部变量将会按照顺序被复制到局部变量表中的每-一个s1ot.上。
●如果需要访问局部变量表中一个64bit的局部变量值时,只需要使用前一个索引即可。(比如:访问1ong或double类型变量)。
●如果当前帧是由构造方法或者实例方法创建的,那么该对象引用this将会存放在index为0的slot处,其余的参数按照参数表顺序继续排列。
更多内容就关注,持续更新
你也可以访问这个地址继续学习:https://www.processon.com/view/6076a7ffe401fd2d66980f5b
更多技术学习请到:https://www.processon.com/view/60504b5ff346fb348a93b4fa