当前位置: 代码迷 >> J2SE >> [讨论]垃圾回收器机制-质疑Think in java,该如何解决
  详细解决方案

[讨论]垃圾回收器机制-质疑Think in java,该如何解决

热度:434   发布时间:2016-04-24 18:02:30.0
[讨论]垃圾回收器机制--质疑Think in java
程序员都知道“初始化”的重要性,但通常忘记清除的重要性。毕竟,谁需要来清除一个int 呢?但是对于
库来说,用完后简单地“释放”一个对象并非总是安全的。当然,Java 可用垃圾收集器回收由不再使用的对
象占据的内存。现在考虑一种非常特殊且不多见的情况。假定我们的对象分配了一个“特殊”内存区域,没
有使用new。垃圾收集器只知道释放那些由new 分配的内存,所以不知道如何释放对象的“特殊”内存。为
解决这个问题,Java 提供了一个名为finalize()的方法,可为我们的类定义它。在理想情况下,它的工作原
理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下
一次垃圾收集过程中,才会真正回收对象的内存。所以如果使用finalize(),就可以在垃圾收集期间进行一
些重要的清除或清扫工作。


上面这段文字是Think in java 4.3 清除:收尾和垃圾收集 一章中的第一段.
主要是想看看大牛们对垃圾回收器的看法, 因此, 没有循证原版Think in java中是怎么样描述这个问题的.
当然, 这个问题也可能是由于jdk的版本引起的误差, 因此, 题目只是想吸引大家进来看看...呵呵

请注意红字标明的部分, 我们可以看出, 作者(或者是翻译的误差? 这里就这么用用吧, 呵呵)认为: 垃圾回收器在运行时, 会首先调用对象的finalize方法, 在下一次垃圾回收器运行时, 释放该对象的内存.

为了照顾各位的情绪, 我还是把问题先在这里描述一下吧, 测试代码在Garbage类中的两个System.gc()的位置, 那里也有些注释的.
* 我对jdk6.0_update_10的GC的运行机制的推测.
* 1. 收集需要回收的对象, 并以某种方式记录下来.
* 2. 调用上次记录在案的需要回收的对象的finalize方法.
* 3. 回收已经调用过finalize方法的需要回收的对象.
* 4. 将已经释放的对象从那个"记录"中移除.
* 下一次运行, 继续1-4的步骤.

我下面引入程序代码(基本上是Think in java中的源代码, 对其中有些东西做了一点小的调整, 效果比较明显一点.):
1. Chair类, 我们就是用它来模拟垃圾的.
Java code
package selfimpr.ThinkInJava.gc;public class Chair {    static boolean gcrun = false;    static boolean f = false;    static int created = 0;    static int finalized = 0;    int i;    Chair() {        i = ++created;        if(created == 35000)            System.out.println("Created 35000");    }    protected void finalize() {        //检测gc的第一次运行,gc第一次运行时调用finalize方法会触发并输出        if(!gcrun) {            gcrun = true;            System.out.println("Beginning to finalize after " +                    created + " Chairs have been ced. ");        }        //监测收集编号i值为35000的Chair对象.        if(i==35000) {            System.out.println("Finalizing Chair #35000, " + "i" + i + " " + created +                    "Setting flag to stop Chair creation");            //当i值为35000的Chair的对象被垃圾收集后, 将f设置为true, 结束创建.            f = true;        }        //记录销毁对象的数目        finalized ++;        if(finalized >= created-100)             System.out.println("All " + finalized + " finalized");    }}

2. 主类, 控制程序监测GC运行
Java code
package selfimpr.ThinkInJava.gc;public class Garbage {    public static void main(String[] args) {        if(args.length == 0) {            System.err.println("Usage: \n" +                    "java Garbage before\n or:\n" +                    "java Garbage after");            return ;        }        //1. Chair.f为假时不断的创建Chair和String对象.        while(!Chair.f) {            new Chair();            new String("To take up space");        }        //结束创建活动后, 打印总共被创建了多少Chair对象.        //在这个过程中, JVM自动运行的垃圾回收回收了多少个Chair对象.        System.out.println("After all Chairs have been created:\n" +                "total created = " + Chair.created +                 ", total finalized = " + Chair.finalized);        if(args[0].equals("before")) {            System.out.println("gc():");            System.gc();            System.out.println("runFinalization():");            System.runFinalization();        }        //这个地方进行了改动, 下面这两行代码是新加的.        //这里我做了两次测试        /*         * 第一次, 调用一次System.gc();         * 第二次, 调用两次System.gc();         * 然而, 和Think in java的讲法不同, 我调用第一System.gc()的时候,          * 程序中没有释放的其他对象的finalize方法并没有被调用.         * 而我调用两次System.gc();所有没有被释放的对象的finalize方法都被调用了.         *          * 因此, 感觉至少在jdk6.0_update_10中, GC的运行是在第二次的时候,         * 才调用finalize方法并释放内存的.         */        System.gc();        System.gc();                //被改动的代码结束                System.out.println("bye!");        if(args[0].equals("after"))            System.runFinalizersOnExit(true);    }}
  相关解决方案