关于《Java编程思想》垃圾回收P89-P90部分补充解释

来源:互联网 发布:网络推广人员岗前培训 编辑:程序博客网 时间:2024/06/06 02:27

P89的代码:

class Book{    boolean checkedOut=false;    Book(boolean checkOut){        checkedOut=checkOut;    }    void checkIn(){        checkedOut=false;    }    protected void finalize(){        if(checkedOut)            System.out.println("Error: checked out");    }}public class TermianationCondition{    public static void main(String args[]){        Book novel=new Book(true);        novel.checkIn();        new Book(true);        System.gc();        }    }}
在原书中主函数的注释让人容易误解摸不到头脑。上面的代码中去掉了所有注释,重新注释:

1.主函数中先声明了一个Book类型的对象引用novel,并在堆中申请了内存空间使novel指向这块空间;

2.接下来调用checkIn方法,使novel指向的对象“被签入”(check in);

3.之后又在内存中申请了一块新的堆空间,这块空间不同于1所申请的空间,且没有明确的引用指向它;

4.调用System.gc(),“建议”JVM(Java Virtual Machine-----Java虚拟机)做清理工作。


这里面涉及了一些问题:

1.垃圾回收,Garbage Collection,简称GC,即为最后的方法调用名称gc的由来。

2.没有“被引用”的对象空间将会被GC认为是“垃圾”,在进行垃圾回收时将会被回收。“被引用”的对象空间则不会被GC回收。

这里“被引用”是指存在某个引用指向对象空间。

3.调用方法System.gc()并不会强制执行垃圾回收。有个非常形象的比喻:

调用System.gc()相当于跟JVM说:“小子,你该回收一下内存了。”但是JVM理不理你,什么时候理你另说。


P90

这一页第三段提到了引用计数法的缺陷,提到了对象之间的循环引用,第四段提到了“交互自引用的对象组”,可以明显感受到这两个是相同的概念。但是还是略显抽象,下面的代码会助于理解:

public class Termination {    public static void main(String args[]) {        Test test_1=new Test();        Test test_2=new Test();                test_1.test=test_2;  //①        test_2.test=test_1;  //②                test_1=null;        test_2=null;    }}public class Test {    Test test;}
所谓对象间的循环引用和“交互自引用的对象组”就是指两个或两个以上的对象相互指向。如上面的代码,①②两行代码使得两个不同的Test类的对象空间相互指向,也就是它们互相引用对方。在主函数最后两行,将两个引用test_1和test_2都置空,这样之前申请的两个Test类的对象空间也就没有了引用指向它们。如果使用引用计数法,由于两个对象空间相互引用(它们各自都指向对方),故而这两个对象的引用计数都不为0,GC无法检测到它们变成了“垃圾”,但实际上它们却应该被回收(因为我们不能再通过引用访问)它们,这就导致了内存泄漏。

清楚了上述所有内容后,在P90第四段中所说的“活”的对象意义也就清晰了——有引用指向/能通过引用来访问的对象即为“活”的对象。

原创粉丝点击