文章目录
运行时数据区概述:
每个线程: 独立包括程序技术器,栈,本地栈
线程间共享: 堆,堆外内存(永久代或元空间,代码缓存)
程序计数器(PC寄存器)–program counter register:
JVM的pc寄存器是对物理pc寄存器的一种抽象模拟
一:pc寄存器作用:
pc寄存器用来存储指向下一条指令的地址,也即将要执行的指令代码,由执行引擎读取下一条指令。
二:两个常见问题:
使用pc寄存器存储字节码指令地址有什么用?
因为cpu需要不停的切换线程,这样切换回来以后就知道从哪开始继续执行。
PC寄存器为什么会被设定为线程私有?
因为各个线程是并发抢占cpu的,为了能够准确记录各个线程正在执行的当前字节码指令地址,让各个线程独立计算,从而不会出现互相干扰。
虚拟机栈–stack:
一个线程对应一个虚拟机栈
一:是什么?
每个线程在创建时创建一个虚拟机栈,其内部保存一个个的栈帧(stack Frame),对应一次次的java方法调用。
二:生命周期:
生命周期和线程一致
三:作用:
主管java程序的运行,保存方法的局部变量(8种基本数据类型,对象的引用地址),部分结果,并参与方法的调用和返回。
四:栈的异常:
- 如果采用固定大小的java栈,那每一个线程的java虚拟机栈容量可以在线程创建的时候独立选定,如果线程请求分配的栈容量超过java虚拟机栈的最大容量,java将会抛出StackOverflowError异常。—递归容易出现
- 如果java虚拟机栈可以动态扩展,并且在尝试扩展的时候无法申请足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,java虚拟机会抛出一个OutOfMemoryError异常。
如何设置栈内存大小:
五:栈的存储单位:
栈中的数据都是以栈帧的格式存在
在这个线程上正在执行的每个方法都各自对应一个栈帧
栈帧是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息。
java栈帧方法有两种返回函数的方式:
- 正常的函数返回,使用return
- 未捕获处理的异常(throws),以抛出异常的方式结束。
六:栈帧的内部结构:
局部变量表(local variables)
定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量
局部变量表存什么:
存放编译期的包含基本数据类型,对象引用,以及returnAddress类型。
-
由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题
-
局部变量表所需的容量大小是在编译期确定下来的
Slot理解:
局部变量表:最基本的存储单元是Slot(变量槽)
- 局部变量表中可知的各种基本数据类型(8种),引用类型(reference),returnAddress类型的变量
- 在局部变量表里,32位以内的类型只占用一个slot(包括returnaddress类型),64位的类型(long和double)占用两个slot
- byte,short,char在存储前被转换为int,boolean也被转换为int,0表示false,非0表示true
- long和double则占据两个slot
- jvm会为局部变量表中的每一个slot都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值
- 当一个实例方法被调用的时候,它的方法参数和方法体内部定义的局部变量将会按照顺序被复制到局部变量表中的每一个slot上
- 如果需要访问局部变量表中一个64bit的局部变量值时,只需要使用前一个索引即可(比如:访问long或double类型变量)
- 如果当前帧是由构造方法或者实例方法创建的,那么该对象引用this将会存放在index为0的slot处,其余的参数按照参数表顺序继续排列。
slot重复利用:
栈帧中的局部变量表的槽位是可以重用的,如果一个局部变量过了其作用域,那么在其作用域之后申明的新的局部变量就很有可能回复用过期的局部变量的槽位,从而节省资源目的。
静态变量和局部变量的对比和小结:
变量的分类:
- 按数据类型分:
- 基本数据类型
- 引用数据类型
- 按类中声明的位置分:
- 成员变量:–按静态与非静态
- 类变量:
- 实例变量:
- 局部变量:
- 成员变量:–按静态与非静态
这里其实是类变量和局部变量的对比
不同点:
-
初始化阶段:
- 类变量:linking的prepare阶段,会给类变量附默认值
- 局部变量:在使用前,必须要进行显式赋值
-
参数表分配: