4.虚拟机栈(线程私有)

一、虚拟机栈的概述(线程私有)

		基于栈 的	设计的,跨平台
		优点:跨平台、指令集小、编译器容易实现
		缺点:性能下降、实现同样的功能 指令集多

1.1、堆管存储、、栈管运行

		虚拟机栈的作用:主管java程序的运行,它保存方法的局部变量、部分结果,并参与方法的返回 和 调用
		局部变量 vs 成员变量(或属性) :
		基本数据类型的变量(8种) vs 引用类型的变量(地址)(类、数组、接口):

1.2、Java虚拟机栈是什么?

		java虚拟机栈,早起叫 java栈
		线程私有的 和 PC寄存器一样在

1.3、 虚拟机栈里存的是什么

		栈帧: 一个栈帧 对应一个 java方法 

1.4、 栈的优点(先进后出、后进先出)

		存储速度很快、仅次于  PC 程序计数器
		只有进栈和出栈  push 和pop
		
		对于栈 是不存在 垃圾回收问题
		不存在 gc  、存在 OOM 

1.5、 面试:开发中遇到的异常有哪些?

		栈溢出,递归常见  StackOverflowError异常
		扩展的时候内存不够了 OutofMemoryError异常
		
		设置虚拟机栈的大小 -Xss256k  后面数字是大小

二、栈的存储单位:栈帧

		多个栈帧构成一个 栈,每个java方法对应一个栈帧,一一对应
		栈帧是一块内存区、是一个数据的集合
	复习: 
		OOP的基本单位:类、对象
		类的基本结构:filed(属性、字段)、method(方法)
-------补充:栈顶就是当前栈帧(当前方法、当前类)
		执行引擎的执行指令只针对  当前栈帧 的
		
		java 方法有两种返回方式:
				一种是 return
				另一种是 抛出异常(没有处理的话) 
				两种方式都会导致 栈帧 被弹出

2.1 栈帧的内部结构

		每个栈帧中存储着:
			·**局部变量表
			·**操作数栈(表达式栈)
				·动态链接(或 指向运行时常量池的方法)
				·方法返回地址(或方法正常退出、或异常抛出)
				·一些附加信息
			后面三个 也叫 帧数据区

2.2 局部变量表(Local veriables)(私有的)

		是一个 数字数组 
		记录 :定义在方法体内的 局部变量  和参数 和 返回值
		因为是线程 私有的 , 所以不会有 线程安全 问题 。
		注意 : 非 静态方法 的话 会有 this 变量 在 index 为0 的位置
-----补充:slot double和long 占据两个 slot位 ,一个是 4位
		栈帧当中的局部变量表的 槽 位 是可以被重复利用的
		出了 作用域 就会被 销毁,后面 定义的变量 就会 占据 被销毁的变量的位置

如图 C占 的槽位(slot位) 就是B用剩下的

-----补充:变量的分类
			变量的分类:
				按照数据类型分:基本数据类型和引用数据类型
				按照在类中声明的位置分:
					成员变量和局部变量(在使用前必须要进行赋值)
						成员变量还可以分为:类变量(static)和实例变量(在使用前都经历过默认初始化赋值)
							类变量:linking给类变量 赋 默认值 ,初始化阶段 给类变量显示赋值(即静态代码块赋值)
							实例变量:随着对象的会在堆 空间中 分配实例变量空间,并进行 默认赋值
-----补充:垃圾回收
			局部变量表中的变量也是 重要的 垃圾回收 根节点,只要被局部变量表中直接或者间接引用的对象对不会被回收

2.3 操作数栈(Operand Stack)(私有的)

		作用:在方法执行的过程当中,根据字节码指令,往 栈 中写入数据(push)和提取数据(pop)
		主要作用:主要用于保存 计算过程中的中间结果,同时作为计算过程中变量 临时的存储空间
		长度 在 编译期 就定义好了
-----补充:代码追踪
代码 1:


图解:第一步
··PC寄存器记录了 下一次要执行的 地址
··将 15 放入操作数栈(int) 中
··紧接着 PC 寄存器 要执行 地址为 2 的代码
··操作数栈 pop 指令, 存入 局部变量表中

图解:第二步
··PC寄存器 要执行索引为 3 的 指令
·· 将8 放入 操作数栈(int) 中
··紧接着 PC 寄存器 要执行 地址为 5 的代码
··操作数栈 pop 指令, 存入 局部变量表中

图解:第三步
··将 6 7 都 压 入操作数栈中 ,pop 执行add

图解:第四步
··执行 add 后 把结果 在 push 进 操作数栈中
··地址为9:pop操作数栈,将 结果 放入 局部变量中

------补充: 栈顶缓存技术(Top-Of-StackCashing)(私有的)
	将栈顶元素全部缓存在 物理CPU的寄存器中,以此降低对内存的读/写速度,从而提升执行引擎的执行效率

2.4 动态链接(Dynamic Linking)

		方法和变量引用 在 常量池中 , 栈帧中的 动态链接里 存的 就是 方法在常量池中的符号引用(地址)
		作用就是:将符号引用转为真实引用 

多个 线程 指向它 , 不存引用的话 ,每个 方法里 得给一份,所以,为了省内存,
存的是引用,指向 常量池 中的真实位置

------补充:方法的调用
静态链接:对应早期绑定  
动态链接:对应晚期绑定:写代码(编译器)的时候确定不下来,例如 接口 =new  ??

-----补充:虚方法和非虚方法
	虚方法表 : (提高方法调用效率)
	
	非虚方法:静态方法、私有方法、final方法、实例构造器、父类方法都是非虚方法(编译器就确定下来了,不存在多态的形式)、、其余的 是 虚方法
	虚方法:和晚期绑定或者动态链接 对应的

-----补充:方法重写本质


2.5 方法返回地址(return address)

		存放调用该方法的PC寄存器的值 

相当于C语言,A调用B ,先把B函数的下一条地址压入A栈里(这里叫PC寄存器),然后B结束之后,好能知道 ,A函数 执行到哪里了

2.6 一些附加信息

------略

二、栈相关面试题

1 举例栈溢出的情况(StackOverflowError)

-Xss 设置栈的大小;OOM

2 如果调整栈的大小,就能保证不出现溢出吗?

答 :不能,死循环(无线递归),溢出错误会出现的晚一些

3 分配栈的内存越大越好吗?

答:不好,只是不容易溢出,但是会出现浪费现象,对自己好,别人用的空间就少了,资源是有限的

4 垃圾回收是否会涉及到虚拟机栈空间嘛?

答:不会的,只有方法区和堆空间 存在GC

5 方法中定义的局部变量会否线程安全?

答:具体问题具体分析,StringBuilder 不安全,StringBuffer 安全的

何为线程安全?

答:如果只有一个线程操作此数据,则线程必安全,如果有多个线程操作同一数据(共享数据),则会出现线程安全问题

posted @ 2021-07-04 18:43  宋佳强  阅读(326)  评论(0编辑  收藏  举报