画布 1
中心主题
  运行时栈帧结构
    局部变量表
      需要多少大小的局部变量表已写入到class字节码方法的Code属性的max_locals属性中
      一个存储单位称为一个Slot(32位)
        为了让所有数据类型的局部变量都能够存储到局部变量表中而设定了定长的Slot长度
          32位以内的数据类型(boolean | byte | char | short | int | float | reference | returnAddress)变量使用1个Slot存储
          32位以上的数据类型(long | double)变量使用2个Slot存储，会以高位对齐的方式进行存储
      局部变量第0位Slot
        实例方法的局部变量表的第0位存储的是用于传递方法所属对象实例的this引用
        静态方法的局部变量表没有这个this引用
      Slot重用：离开了作用域的局部变量占用的Slot可以被重用
        对垃圾回收的影响：离开了作用域的局部变量所在的Slot只有在真的不存在对原有局部变量的引用时，GC才会回收相应的对象实例
          花括号内的局部变量a在花括号外出了作用域，直接GC也不会回收a，就是由于这时还是存在Slot对a的引用
          花括号内的局部变量a在花括号外出了作用域，花括号外再有一个局部变量赋值导致Slot被重用了，GC就会回收a，就是由于Slot对a的引用没有了
      局部变量和类字段的区别
        生命周期不同
          类字段的生命周期是类的生命周期
          局部变量的生命周期是方法中变量的生命周期
        赋初值不同
          类字段会在类加载的准备阶段赋零值，再会在类加载的初始化赋初值
          局部变量的初值如果没有手动赋值的话是没有的，编译阶段即会报出未初始化就使用的错误
      reference类型
        可以从reference类型变量中直接或间接地查找到对象在Java堆中存放的起始地址索引
        可以从reference类型变量中直接或间接地查找到对象所属类型在方法区中的类的存储信息
    操作数栈
      需要多大的栈深度已写入到class字节码方法的Code属性的max_stacks属性中，任何时候栈容量都不能超过最大栈深度
      一个存储单位称为一个栈容量
        为了让所有数据类型的局部变量都能够存储到栈中而设定了定长的栈容量
          32位以内的数据类型(boolean | byte | char | short | int | float | reference | returnAddress)变量使用栈容量为1
          32位以上的数据类型(long | double)变量使用栈容量为2
    动态链接
      为了满足方法指令的运行时解析
        静态解析：把方法调用指令中的符号引用在类加载或首次运行时转换为直接引用，即这些方法引用是静态可确定的引用
        动态链接：把方法调用指令中的符号引用在运行时才转换为直接引用，即这些方法引用是动态运行时才可确定的
    方法返回地址
      退出方法的方式
        正常返回出口：执行到返回指令字节码的时候会将方法返回值传递给上层的方法调用者
        异常完成出口：方法执行遭遇异常，如JVM内部异常或者athrow字节码指令，且在异常表中未找到匹配处理器导致退出，不会给上层的方法调用者任何返回值
      退出方法执行的操作
        恢复上层方法的局部变量表
        把返回值压入调用者栈帧的操作数栈
        调整PC计数器的值指向方法调用指令的后一条指令
  基于栈的字节码执行
    P327有详细的字节码过程
  方法调用
    方法执行的步骤
      方法编译：将源码编译称class字节码中的符号引用
      方法调用：将class字节码中的符号引用解析成直接引用
      方法执行：执行解析出的直接引用指向地址的方法
    虚方法和非虚方法
      非虚方法：在类加载的时候就可以将符号引用解析为直接引用的方法，即不存在因覆盖而产生多版本的方法
        静态方法
        实例构造器<init>方法
        私有方法
        父类方法
        final方法
      虚方法：在类加载的时候有可能无法确定符号引用可以解析为哪个直接引用的方法
        因覆盖父类方法而出现的多版本方法无法在类加载时就确定方法的直接引用
        目前没有产生覆盖的方法虽然不存在多版本但是也归为了虚方法，因为它可能会被新类覆盖方法
    5种方法调用字节码
      invokestatic
        静态方法
      invokespecial
        实例构造器<init>方法
        私有方法
        父类方法
      invokevirtual
        final方法
        虚方法
      invokeinterface
        接口方法，会在运行时再确定实现接口的对象
      invokedynamic
        运行时动态解析出调用点限定符所引用的方法再执行
    分派 Dispatch
      静态分派 Method Overload Resolution
        编译期即可确定方法的版本
        由编译器直接解析来完成方法版本的判定，不需要虚拟机介入
        典型应用是方法重载 Overload
          重载：方法签名不同（方法名相同、参数列表不同）
          编译阶段就会将重载方法调用解析为 invokevirtual 选择的方法版本的符号引用
          方法m(Q)重载了方法m(P)，编译器解析名为m的方法时会根据其参数p的静态类型(即外观类型或者直接类型)来选择方法的版本
          如果参数是无显式的静态类型的字面量，那么编译期会最大可能地去推断字面量最贴近的参数类型。如print(‘a’)解析为重载的方法版本print(char) print(int)时会优先推断字面量类型为char选择前者，如果没有前者定义的话才会选择后者
      动态分派
        运行期才可确定方法的版本
        由虚拟机来完成方法版本的判定
        典型应用是方法重写 Override
          重写：方法签名相同（方法名相同、参数列表相同）
          编译阶段就会将重写方法调用解析为 invokevirtual 选择的方法版本的符号引用
          类B的方法m(P)重写了B所继承的类A的方法m(P)，实际类型为B，A b = new B()，即静态类型为A的对象b，发生了方法调用b.m(p)
            编译期：编译器将b.m(p)编译成了invokevirtual A.m
            运行期
              找到操作数栈顶的第一个元素指向对象即b的实际类型，也就是B
              在B中寻找与invokevirtual调用的方法符号引用名称和签名一致的方法
                找到了的话说明实际类型B中就有了这个方法m(P)，然后判定该方法是否满足访问权限
                  满足：将调用的方法符号引用替换为该方法的直接引用
                  不满足：抛出java.lang.illegalAccessError异常
                没找到
                  在B的父类中自下向上寻找与invokevirtual调用的方法符号引用名称和签名一致的方法
                    找到了的话说明实际类型B的父类中有这个方法m(P)，然后判定该方法是否满足访问权限
                      满足：将调用的方法符号引用替换为该方法的直接引用
                      不满足：抛出java.lang.illegalAccessError异常
                    始终没找到：抛出java.lang.AbstractMethodError异常
    方法宗量：方法的接收者(所有者)和参数
      单分派：根据单个方法宗量进行方法选择
        静态阶段(编译期)的选择过程是依据方法的接收者和方法的参数两个总量来选择的，因此静态阶段多分派
      多分派：根据多个方法宗量进行方法选择
        动态阶段(运行时)的选择过程是依据方法的接收者来选择的，因此动态阶段单分派
    虚拟机动态分派的实现
      搜索虚方法的合适版本：代价太大
      稳定优化手段：虚方法表 提前记录避免运行时搜索的手段
        父类类加载时准备虚方法表，虚方法表将每个虚方法的表中索引指向方法区中的类信息的方法实际地址
        子类类加载时准备虚方法表，虚方法表将重写的方法指向子类在方法区中类信息的方法实际地址，而未重写的方法仍旧指向其父类方法区中的类信息的方法实际地址
        调用虚方法时可以直接获取到这个方法的实际地址而免去了搜索过程
      非稳定的激进优化手段
        内联缓存
        基于“类型继承关系分析”技术的守护内联