Java虚拟机——运行时栈帧

栈帧是虚拟机运行时数据区中的虚拟机栈的栈元素,栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。

  1. 局部变量表
    局部变量表用于存放方法参数和方法内部定义的局部变量。
    局部变量表的容量以变量槽Slot为最小单位,一个Slot可以存放一个32位以内的数据类型,对于64位的数据类型,虚拟机会以高位在前的方式为其分配两个连续的Slot空间。
    虚拟机通过索引定位的方式使用局部变量表,索引值的范围是从0开始到局部变量表最大的Slot数量。
    在方法执行时,虚拟机是使用局部变量表完成参数值到参数变量列表的传递过程的,如果是实例方法(非static方法),局部变量表中第0位索引的Slot默认用于传递方法所属对象实例的引用,可以通过关键字“this”来访问。
    变量体中定义的变量,其作用域并不一定会覆盖整个方法体,如果当前字节码PC计数器的值超出某个变量作用域,那么这个变量对应的Slot就可以交给其他变量使用,在某些情况下Slot的复用会影响到系统的垃圾收集行为。参照以下三段代码
//代码段1
    public static void main(String[] args){
        byte[] b = new byte[64 * 1024 * 1024];
        System.gc();
    }
//代码段2
public static void main(String[] args){
    {
        byte[] b = new byte[64 * 1024 * 1024];
    }
    System.gc();
}
//代码段3
    public static void main(String[] args){
        {
            byte[] b = new byte[64 * 1024 * 1024];
        }
        int a = 0;
        System.gc();
    }     

以上代码中,代码块3中会将变量b的空间进行回收,代码块1和代码2则不会,代码块2中不会回收的原因是:代码虽然离开了b的作用域,但后期没有任何对局部变量表的读写操作,b原本所占用的Slot还没有被其他变量所复用,所以作为GC Roots一部分的局部变量表仍然保持着对它的关联。

  1. 操作数栈
    操作数栈也被称为操作栈,后入先出。32位数据类型所占的栈容量为1,64位数据类型所占栈容量为2.。当一个方法刚刚开始执行的时候,这个方法的操作数栈为空。

  2. 动态连接
    每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。Class文件的常量池中存有大量符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化称为静态解析。另外一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

4.方法返回地址
当一个方法被执行后,有两种方式退出。第一种为正常退出,即正常完成出口;第二种方式为异常退出,即异常完成出口。
方法退出的过程实际上等同于把当前栈帧出栈,可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用者栈帧的操作数栈中,调整PC计数器的值以指向方法调用指令后面的一条指令。

发布了10 篇原创文章 · 获赞 0 · 访问量 75

猜你喜欢

转载自blog.csdn.net/qq_39126079/article/details/104300154
今日推荐