一次有趣的局部变量GC

前言

最近在看《实战Java虚拟机》, 发现书上的一个关于局部变量表GC挺有意思,先上代码。java

主角

没有GC

public class Main {
    public static void reversion(){
        {
            byte[] a = new byte[6*1024*1024];
        }
        System.gc();
    }

    public static void main(String[] args) {
        reversion();
    }
}

分配了一块6MB的堆空间,并使用局部变量引用这块空间, 而后显式进行一次Full GC。数组

image-20181029192234982

先配置一下JVM参数用于打印GC log函数

能够看到这块6MB的堆空间并无被回收, 接下来加一行代码就能使得堆空间被回收。工具

能够GC

public class Main {
    public static void reversion(){
        {
            byte[] a = new byte[6*1024*1024];
        }
        int c = 0;
        System.gc();
    }

    public static void main(String[] args) {
        reversion();
    }
}

能够看到这6MB的空间已经被回收了,仅仅由于多了一句看似与a毫无关系的 int c = 0;学习

答案

借助jclasslib工具咱们进一步查看函数的局部变量信息, 在此以前咱们须要对代码作一点小改动再进行分析spa

public class Main {
    public static void reversion(){
        {
            byte[] a = new byte[6*1024*1024];
            System.out.println(a[0]);
        }
        int c = 0;
        System.gc();
    }

    public static void main(String[] args) {
        reversion();
    }
}

tips:JVM即时编译器拥有死代码消除的特性,a数组并无被任何地方使用,即时编译器能够精简数据流,而且减小编译时间以及最终生成机器码的大小。简单的说若是a没有被使用的话会被编译成var0, 咱们在本地变量表中看不到a了。code

能够看到a和c在局部变量表中的索引值都是0,也就是说c重用了a在局部变量表中的槽位,从而使得a指向的堆空间可以被GC回收索引

栈帧中的局部变量表中的槽位是能够重用的,若是一个局部变量过了其做用域,那么在其做用域以后申明的新的局部变量就颇有可能复用过时局部变量的槽位,从而达到节省资源的目的ip

总结

经过这个GC的小例子,切实感觉到了JVM对于资源节省的严苛程度,对于做用域的细粒度把控之强大。给你们推荐我读的这本《实战Java虚拟机》,切实的一本好书,所谓好书无非两点:1.能读懂 2.有所获。同时也推荐极客时间的《深刻拆解虚拟机》,多路学习,兼听则明。ssl

最后打个小广告~

相关文章
相关标签/搜索