java局部变量对垃圾回收的影响

作者: winwill2012 | 来源:发表于2015-05-04 21:10 被阅读1020次

    结论

    局部变量表中的变量是很重要的垃圾回收根节点,被局部变量表中变量直接或者间接引用的对象都不会被回收。

    实验

    看如下代码,使用JVM的-XX:+PrintGC参数运行下面代码(在main函数中分别执行localVarGcN的每一个函数)

    package com.winwill.jvm.basic;
    public class GcTest {
        private static final int SIZE = 6 * 1024 * 1024;
        public static void localVarGc1() {
            byte[] b = new byte[SIZE];
            System.gc();
    }
        public static void localVarGc2() {
            byte[] b = new byte[SIZE];
            b = null;
            System.gc();
        }
        public static void localVarGc3() {
            {
                byte[] b = new byte[SIZE];
            }
            System.gc();
        }
        public static void localVarGc4() {
            {
                byte[] b = new byte[SIZE];
            }
            int c = 0;
            System.gc();
        }
        public static void localVarGc5() {
            localVarGc1();
            System.gc();
        }
        public static void main(String[] args) {
    //        localVarGc1();   // 没有GC
    //        localVarGc2();   // GC
    //        localVarGc3();   // 没有GC
    //        localVarGc4();   // GC
    //        localVarGc5();   // GC
        }
    }
    

    在main中分别执行localVarGc[1-5]方法,得到如下5次gc日志:

    [GC (Allocation Failure) 512K->374K(130560K), 0.0006220 secs]
    [GC (Allocation Failure) 886K->600K(130560K), 0.0011130 secs]
    [GC (Allocation Failure) 1112K->752K(130560K), 0.0006960 secs]
    [GC (Allocation Failure) 1264K->950K(131072K), 0.0015540 secs]
    [GC (System.gc()) 7944K->7363K(131072K), 0.0008640 secs]
    [Full GC (System.gc()) 7363K->7116K(131072K), 0.0085270 secs]
    [GC (Allocation Failure) 512K->390K(130560K), 0.0008690 secs]
    [GC (Allocation Failure) 902K->592K(130560K), 0.0008500 secs]
    [GC (Allocation Failure) 1104K->718K(130560K), 0.0007220 secs]
    [GC (Allocation Failure) 1230K->924K(131072K), 0.0012260 secs]
    [GC (System.gc()) 7919K->7309K(131072K), 0.0018500 secs]
    [Full GC (System.gc()) 7309K->975K(131072K), 0.0059300 secs]
    [GC (Allocation Failure) 512K->374K(130560K), 0.0007940 secs]
    [GC (Allocation Failure) 886K->598K(130560K), 0.0007240 secs]
    [GC (Allocation Failure) 1110K->718K(130560K), 0.0007680 secs]
    [GC (Allocation Failure) 1230K->916K(131072K), 0.0009900 secs]
    [GC (System.gc()) 7887K->7340K(131072K), 0.0008910 secs]
    [Full GC (System.gc()) 7340K->7116K(131072K), 0.0091600 secs]
    [GC (Allocation Failure) 512K->416K(130560K), 0.0007990 secs]
    [GC (Allocation Failure) 928K->584K(130560K), 0.0008580 secs]
    [GC (Allocation Failure) 1096K->728K(130560K), 0.0007360 secs]
    [GC (Allocation Failure) 1240K->910K(131072K), 0.0010150 secs]
    [GC (System.gc()) 7883K->7339K(131072K), 0.0011770 secs]
    [Full GC (System.gc()) 7339K->971K(131072K), 0.0069840 secs]
    [GC (Allocation Failure) 512K->406K(130560K), 0.0005700 secs]
    [GC (Allocation Failure) 918K->622K(130560K), 0.0011430 secs]
    [GC (Allocation Failure) 1134K->710K(130560K), 0.0015010 secs]
    [GC (Allocation Failure) 1222K->948K(131072K), 0.0020340 secs]
    [GC (System.gc()) 7921K->7304K(131072K), 0.0013160 secs]
    [Full GC (System.gc()) 7304K->7110K(131072K), 0.0091750 secs]
    [GC (System.gc()) 7121K->7142K(131072K), 0.0002990 secs]
    [Full GC (System.gc()) 7142K->966K(131072K), 0.0050000 secs]

    从上面的gc日志中(加粗部分为System.gc触发的)可以得到如下结论:

    1. 申请了一个6M大小的空间,赋值给b引用,然后调用gc函数,因为此时这个6M的空间还被b引用着,所以不能顺利gc;
    2. 申请了一个6M大小的空间,赋值给b引用,然后将b重新赋值为null,此时这个6M的空间不再被b引用,所以可以顺利gc;
    3. 申请了一个6M大小的空间,赋值给b引用,过了b的作用返回之后调用gc函数,但是因为此时b并没有被销毁,还存在于栈帧中,这个空间也还被b引用,所以不能顺利gc;
    4. 申请了一个6M大小的空间,赋值给b引用,过了b的作用返回之后重新创建一个变量c,此时这个新的变量会复用已经失效的b变量的槽位,所以b被迫销毁了,所以6M的空间没有被任何变量引用,于是能够顺利gc;
    5. 首先调用localVarGc1(),很显然不能顺利gc,函数调用结束之后再调用gc函数,此时因为localVarGc1这个函数的栈帧已经随着函数调用的结束而被销毁,b也就被销毁了,所以6M大小的空间不被任何对象引用,于是能够顺利gc。

    相关文章

      网友评论

      • Mooner_guo:用{}括起来怎么会放到栈帧中呢?

      本文标题:java局部变量对垃圾回收的影响

      本文链接:https://www.haomeiwen.com/subject/dmqifttx.html