jvm虚拟机栈 笔记3

内存

jvm内存布局规定了 java运行时内存申请,分配、管理相关策略,保证了jvm搞笑稳定运行。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XF2p2GBs-1604235961089)(en-resource://database/5081:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vTHyMUQL-1604235961094)(en-resource://database/5083:1)]

每个线程:独立包括程序计数器,栈、本地栈
线程间共享:堆、堆外内存
每个jvm只有一个runtime 运行时环境

线程

一个程序里的运行单元 jvm允许多线程并行
在hotspot jvm里每个线程都与操作系统本地线程直接映射

  1. 虚拟机线程
  2. 周期任务线程
  3. GC线程
  4. 编译线程 字节码编译成本地代码
  5. 信号调度线程

program counter register

jvm中的pc寄存器是对物理pc寄存器的抽象模拟

用来存储指向下一条指令的地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ghvX5W7-1604235961097)(en-resource://database/5085:1)]

任何时间一个线程只有一个方法在执行 程序计数器会村粗当前线程正在执行的java方法的jvm指令地址,如果在执行native方法,则为指定值
没有OOm gc情况
线程私有

虚拟机栈

java的指令根据栈来设计的 不同平台cpu架构不同,所以不能设计为基于寄存器
栈解决程序的运行问题,堆解决数据的存储

每个线程创建时都会创建一个虚拟机栈,其内部保存一个个栈帧,Stack Frame 对应一个java 方法
线程私有
没有gc

作用

主管程序的运行,保存方法的局部变量(8种 对象的引用地址)、部分结果,并参与方法的调用和返回
局部变量 vs 成员变量
基本数据变量 vs 引用类型变量(类、数组、接口)

栈的存储单位

每个线程有自己的栈 栈中的数据以栈帧为单位
每个方法对应一个栈帧
在一条活动的线程中,一个时间点上,只有一个活动的栈帧
执行引擎运行的所有字节码指令只针对当前栈帧操作
如果该方法中调用了其他方法,对应的栈帧会被创建出来,放在栈顶
方法返回之际,当前栈传回此方法的返回结果,给前一个栈
java两种返回方式,一正常return 放回,二抛出异常

栈帧的内部结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fYQUcJjP-1604235961124)(en-resource://database/5092:0)]

  1. 局部变量表
    数字数组用于方法参数和定义在方法体内的局部变量
    基本单位slot
    基本类型8种 引用类型 returnAddress
    * 可以重复利用
    32位占一个
    64 long double 占两个
    jvm为局部变量 中的每个slot 分配一个访问索引,通过索引访问局部变量表中指定的局部变量值
    当一个示例方法被调用的时候 他的方法参数和方法体内部定义的局部变量按照顺序被复制大局部变量表中的每个solt
    当为构造方法或实例方法创建的,那么该对象引用this将会放在index为0的solt,其余参数按照参数表顺序继续排列

    变量 : 数据类型
    1. 基本数据类型 2.引用数据类型
    声明方式
    1. 类变量 默认初始化
    2. 局部变量

  2. 操作数栈 operand stack
    后进先出
    如果调用方法有返回值的话,其返回值会被压入当前栈帧的操作数栈中并更新pc寄存器下一条 需要执行的字节码指令
    操作数战中的元素数据类型与字节码指令的序列严格匹配 在编译其编译阶段进行验证 在雷佳在过程中类检验阶段的数据分流阶段要再次验证

    • 我们所说的java虚拟机 的解释引擎是基于栈的执行引擎 指操作数栈
      每一个操作数栈有个明确栈深度用于存储数值,
      保存计算过程中间结果,
  3. 动态链接
    每一个栈帧内部都包含一个指向运行时常量池中改栈帧所属方法的引用
    在java源文件被编译到字节码文件中时,所有变量和方法引用都作为符号引用保存在class文件的常量池里

    • 为了将这些符号引用转化我调用方法的直接引用
  4. 方法返回地址

    1. 存放调用该方法的pc寄存器的值,方法正常退出 调用该方法的指令下一条指令的地址 异常退出 返回地址通过异常表来确定

    2. 在方法执行后,有两种方式退出这个方法,就行使用哪一个指令还是要根据方法返回值得实际数据类型而定

      1. ireturn (boolean byte char short int )
      2. lreturn
      3. freturn
      4. dreturn
      5. areturn
      6. 供void 实例化初始化方法,类 接口的初始化方法使用

      方法执行过程中遇到了异常,一场没有在方法内进行处理,本方法的异常表中没有搜索到异常处理器 就会导致方法退出
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rX8CM6Yq-1604632055422)(en-resource://database/5096:0)]

      本质上说方法的退出就是当前栈帧出栈的过程,此时需要恢复上层方法的局部变量表,操作数栈,将返回值压入调用者当前栈的操作数栈,设置pc寄存器等,让方法得以继续执行

  5. 一些附加信息

栈顶缓存技术

操作数存储在内存中 频繁执行内存读写影响执行。 提出将栈顶元素全部缓存在cpu寄存器中,以此降低对内存读写次数,提升执行引擎的执行效率

常量池

为了提供一些符号和常量 便于指令识别

引用转换

符号引用转换为调用方法的直接引用与方法的绑定机制相关
静态链接
在被调用的目标方法在编译器可知,切运行期保持不变
动态链接
再被调用编译期间无法确定下来 只能在运行期将调用方法的符号引用转换

绑定机制

早期绑定 晚期绑定 绑定一个字段 方法 类在符号引用被替换为直接引用,
晚期绑定 编译期无法被确定 只能在运行时确定

虚方法 非虚方法

在编译期确定了具体的调用版本 运行时不变
静态 私有 final 实例构造器 父类都是非虚

方法调用

重写的本质
  1. 找到操作数栈顶的第一个元素所执行对象的实际类型,
  2. 找到与常量中描述符合的简单名称都相符的方法,则进行权限校验,如果通过返回这个方法的直接引用,不通过报错IllegalAccessError
  3. 否则 按照继承关系查找各个父类 进行第二步
  4. 最后没有找到 抛出AbstractMethodError
虚方法表

频繁的使用动态分派,每次动态分派都要重新在类的方法元数据中搜索合适的目标会影响执行效率
非虚方法不会再表中,使用索引表查找
在类加载链接阶段

指令

普通调用
invokestatic 调用静态
invokespecial 私有 父类
invokevirtual 所有虚方法
invokeinterface 调用接口
动态调用
invokedynamic 动态解析出需要调用

动态 静态类型语言

对于类型的检查是在编译期

e

IllegalAccessError 试图访问修改一个属性或一个方法,你没有权限访问
constant pool 常量池
symbolic reference 符号引用
Local Variable本地变量表
Operand Stack 操作数栈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值