摘要:前言最近在看实战虚拟机发现书上的一个关于局部变量表挺有意思,先上代码。主角没有分配了一块的堆空间,并使用局部变量引用这块空间然后显式进行一次。
前言
最近在看《实战Java虚拟机》, 发现书上的一个关于局部变量表GC挺有意思,先上代码。
主角 没有GCpublic 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。
先配置一下JVM参数用于打印GC log
可以看到这块6MB的堆空间并没有被回收, 接下来加一行代码就能使得堆空间被回收。
可以GCpublic 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工具我们进一步查看函数的局部变量信息, 在此之前我们需要对代码做一点小改动再进行分析
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了。
可以看到a和c在局部变量表中的索引值都是0,也就是说c重用了a在局部变量表中的槽位,从而使得a指向的堆空间能够被GC回收
栈帧中的局部变量表中的槽位是可以重用的,如果一个局部变量过了其作用域,那么在其作用域之后申明的新的局部变量就很有可能复用过期局部变量的槽位,从而达到节省资源的目的
总结通过这个GC的小例子,切实感受到了JVM对于资源节省的严苛程度,对于作用域的细粒度把控之强大。给大家推荐我读的这本《实战Java虚拟机》,切实的一本好书,所谓好书无非两点:1.能读懂 2.有所获。同时也推荐极客时间的《深入拆解虚拟机》,多路学习,兼听则明。
最后打个小广告~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/71928.html
摘要:垃圾回收及一次内存泄漏处理内存分布上图展示了的架构图,本篇我们主要关注,运行时数据区。但是垃圾回收并不能百分百保证不会出现内存泄漏,所以了解垃圾回收,对于我们遇到内存泄漏时能更加清晰的分析原因,也能帮助我们写出更加安全,可靠的程序。 [toc] JAVA GC垃圾回收(及一次内存泄漏处理) showImg(https://segmentfault.com/img/remote/1460...
阅读 2749·2021-11-25 09:43
阅读 2110·2021-11-18 13:25
阅读 4571·2021-09-22 15:52
阅读 1869·2021-09-22 15:49
阅读 2215·2019-08-30 15:54
阅读 3010·2019-08-29 17:13
阅读 2317·2019-08-29 16:54
阅读 2258·2019-08-29 12:58