Thinking in java自读笔记:finalize()方法的作用

关于finalize与垃圾回收的两个注意点:
(一)finalize是在垃圾回收之前被调用,但不一定会被调用
(二)垃圾回收只与内存有关

一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存。但值得注意的一点是,并不是所有的废弃对象都会被垃圾收集器收集,如果不是内存即将耗尽,垃圾收集器不会去自动释放内存,因为释放内存也需要占用资源,当然可以强行调用GC。
测试代码如下:

import java.util.LinkedList;

public class Test {
    public static void main(String[] args)
    {
        LinkedList<Student> ls=new LinkedList<Student>();
        for(int i=0;i<10;i++)
        {
            new Student(i);
        }
        System.gc();
       // System.runFinalization();
    }
}
class Student
{
    int i;
    Student(int num)
    {
        this.i=num;
    }
    @Override
    protected void finalize() {
        System.out.println("编号i="+i+"被清除");
    }
}

在测试代码中,用一个循环生成了指定数量的“废弃”Student对象,强制调用GC观察输出结果。如果指定的数量比较大,GC会自动调用,输出的结果如下:

在输出中我们可以看到,10个”废弃”对象只有6个被清除掉,因此finalize并不是一定会被执行的(废弃对象不一定会被释放掉),如果将// System.runFinalization()注释取消掉,输出结果如下
这里写图片描述
我们可以看到所有”废弃”对象全部被清除掉,但在这里的所有废弃对象是收集到的所有对象,假如我把对象数量设置很大,并且用一个数来保存释放掉的数量,代码如下:

import java.util.LinkedList;

public class Test {
    public static void main(String[] args)
    {
        LinkedList<Student> ls=new LinkedList<Student>();
        for(int i=0;i<1000000;i++)
        {
            new Student(i);
        }
        System.gc();
        System.runFinalization();
        System.out.println(Student.num);
    }
}
class Student
{
    static int num=0;
    int i;
    Student(int num)
    {
        this.i=num;
    }
    @Override
    protected void finalize() {
        System.out.println("编号i="+i+"被清除");
        num++;
    }
}

输出如下:

根据结果,可以明显的看到1000000个对象只释放掉了999992个对象,因此我感觉垃圾回收器在100万个“废弃”对象中只收集到了999992个。
总结“废弃”对象在垃圾回收时不一定会被释放掉,运行System.gc()和System.runFinalization()可以释放掉所有收集到的”废弃”内存,单独运行System.runFinalization()貌似无作用。

浅谈一下我对System.runFinalization()和System.gc()的理解:System.runFinalization()并不是强行调用finalize方法,在官方文档中说的是:Java虚拟机花费了精力来运行被发现丢弃的对象的最终方法,如果GC都没有去收集发现,又何从运行最终方法呢!!!但是单独调用System.gc()和“组合”调用又有释放对象的差别:我对此的个人理解为:垃圾回收器收集到了“废弃”的对象,并不是能收集到所有的“废弃”,当单独调用System.gc()时,从收集到的对象中释放一部分,保证当前进程的正常运行,为什么不释放完,可能是因为释放也需要占用资源,当能保证进程运行的情况下,没有那个必要。当组合调用时,System.runFinalization()调用垃圾回收器收集到的所有”废弃”对象的finalize()方法。

猜你喜欢

转载自blog.csdn.net/qq_27368993/article/details/82659416