深入理解Java虚拟机——局部变量表

x33g5p2x  于2022-03-25 转载在 Java  
字(1.4k)|赞(0)|评价(0)|浏览(135)

一、局部变量表的概述

  • 局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。
  • 在jav程序编译为Class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的局部变量表的最大容量。
  • 局部变量表的容量以变量槽(Variable Slot)为最小单位,虚拟机规范中并没有明确指明一个Slot应占用的内存空间大小,只是很有导向性的说到每个Slot都应该存放一个boolean、byte、char、short、int、float、reference或renturnAddress类型的数据,这8中数据类型。
  • 为了尽可能的节省栈帧空间,局部变量表中的Slot是可以重用的。

二、reference类型的概述

  • reference类型表示对一个对象实例的引用。
  • 虚拟机实现至少都应当能通过这个引用做到两点:
    (1)、从此引用中直接或间接地查找到对象在Java堆中的数据存放的起始地址索引。
    (2)、从此引用中直接或间接地查找到对象所属数据类型在方法区中的存储的数据类型。

三、renturnAddress类型的概述

  • renturnAddress类型目前已经很少见了,它是为了字节码指令jsr、jsr_w和ret服务的,指向了一条字节码指令的地址。

四、局部变量表中Slot槽复用对垃圾回收的影响

4.1、局部变量表中Slot槽复用对垃圾回收的影响(一)

  • 源码
public class Test {
    public static void main(String[] args) {
        byte[] a = new byte[64 * 1024 * 1024];
        System.gc();
    }
}
  • 输出结果

  • 总结
    向内存中填充了64MB的数据,虚拟机运行参数中添加“-verbose:gc”,发现System.gc()运行后并没有回收这64MB的内存,因为在执行System.gc()时,变量a还处于作用于内,虚拟机自然不敢回收a的内存。

4.2、局部变量表中Slot槽复用对垃圾回收的影响(二)

  • 源码
public class Test {
    public static void main(String[] args) {
        {
            byte[] a = new byte[64 * 1024 * 1024];
        }
        System.gc();
    }
}
  • 输出结果

  • 总结
    加入了花括号之后,a变量的作用域被限制在花括号内,从代码逻辑上讲,在执行System.gc()的时候,a已经不可能在被访问了,但运行接口还是有64MB的内存没有被回收。
    因为代码虽然已经离开了a的作用域,但在此之后,没有任何对局部变量表的读写操作,a原本所占用的Slot还没有被其他变量所复用,所以作为GC Roots一部分的局部变量表仍然保持这对它的关联

4.3、局部变量表中Slot槽复用对垃圾回收的影响(三)

  • 源码
public class Test {
    public static void main(String[] args) {
        {
            byte[] a = new byte[64 * 1024 * 1024];
        }
        int b =0;
        System.gc();
    }
}
  • 输出结果

  • 总结
    从输出结果看,这次内存真的被正确回收了。说明手动将其设置为null值的操作在某系情况下确实是有用的。

4.4、总结

  • 示例中a变量能否被回收的根本原因是:局部变量表中的Slot是否还存有关于a数组对象的引用。

相关文章