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

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第四段中所说的“活”的对象意义也就清晰了——有引用指向/能通过引用来访问的对象即为“活”的对象。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值