运行时栈帧之局部变量表

Slot单元的可重用性

局部变量表的容量以slot为最小单位,一个slot可以存放32位数据类型,局部变量表中的slot是可以重用的,举个例子

    public static void main(String[] args) {
        {
            byte[] pc = new byte[64*1024*1024]; // 64兆
        }
        System.gc();
    }

pc变量外加{}以保证执行gc的时候pc不在作用域内,让gc回收掉pc,但是结果是

[GC (System.gc())  68485K->66336K(186880K), 0.0009442 secs]
[Full GC (System.gc())  66336K->66219K(186880K), 0.0055352 secs]

还是有66219K=64.67M的内存没有被回收,也就是pc没有被回收,但是当我们加一行看似无所关联的语句:

    public static void main(String[] args) {
        {
            byte[] pc = new byte[64*1024*1024];
        }
        int a = 0; // 新加的语句
        System.gc();
    }

结果是

[GC (System.gc())  68485K->66392K(186880K), 0.0016273 secs]
[Full GC (System.gc())  66392K->683K(186880K), 0.0065779 secs]

回收后仅剩余683K,也就是pc对象已经被回收了,其原因就是在例1中pc虽然和gc不在同一域,但是在pc定义后没有任何堆局部变量表的读写操作,pc原占有的64M内存还没被其他的变量所复用,并不会被垃圾收集,所以对某些大变量没用了得时候,手动设置为null值以便gc准确的把他回收掉是有意义的,但是置空不能作为编码规范来提倡,以恰当的变量作用域来控制变量回收才是优雅的做法,如不控制变量作用域的话:

    public static void main(String[] args) {
        byte[] pc = new byte[64*1024*1024];
        int a = 0;
        System.gc();
    }

其结果是

[GC (System.gc())  69468K->66336K(186880K), 0.0013088 secs]
[Full GC (System.gc())  66336K->66223K(186880K), 0.0069420 secs]

pc并没有被回收
注:此例中JVM的参数是

-verbose:gc

表示的含义是在:虚拟机发生内存回收时在输出设备显示信息

局部变量必须初始化

类变量在类加载的准备阶段赋予变量初始值,在初始化阶段赋予变量程序定义值,也就是没有为类变量赋值也没有关系,类变量还是具有一个明确的初始值,但是局部变量就不一样了了,如果没有明确赋值,一个局部变量是不能使用的

    public static void main(String[] args) {
        int a;
        System.out.println(a);
    }

这个代码在编译期间就报错了

The local variable a may not have been initialized

你可能感兴趣的:(内存管理)