JAVA垃圾回收 之 引用计数 之 循环引用

2 篇文章 0 订阅

今天想记录一个东西所以登陆了下博客,发现居然有人评论。但是这篇博客满篇错误实在不忍直视。。。

为挽尊,尝试用c++智能指针解释一下这个问题。。。

假设:

class A {

 shared_ptr<B> pb_;

}

class B {

 shared_ptr<A> pa_;

}


调用方:

{

 shared_ptr<A> pa(new A);

 shared_ptr<B> pb(new B);

 pa->pb_ = pb;

 pb->pa_ = pa;

}

出了大括号以后,pa和pb生命期到期,让对象 A 和 B 的引用计数都降为1.

问题在于,成员变量 pa_ 和 pb_ 是没有办法减低引用计数的,

为什么呢,因为它们在对象 A 和 B 里面啊,也就是在堆上啊。

所以就只能互相引用到天荒地老。


为避免这个问题,c++中会将互相引用的两个对象中,其中一个引用 weak_ptr,

因为 weak_ptr 不会使引用计数加1,所以就不会出现这种互相拖着对方的事情了。


以下对比没有循环引用的情况:

class A {

 shared_ptr<C> pc_;

}

class C {

}

调用方:

{

 shared_ptr<A> pa(new A);

 shared_ptr<C> pc(new C);

 pa->pc_ = pc;

}

出了大括号以后,pa和pc生命期到期,让对象 A 的引用计数降为 0,C 的引用计数降为1.

然后堆上的 A 完成使命高高兴兴的析构,此时 pc_ 的生命期到期,使 C 的引用计数降为0,所以 C 也开开心心析构了。


。。。。。。。。。。。不知道这次有没有理解正确。。。。。。。。。。大哭



===========================================羞耻的分界线=====================


。。。java鸟蛋表示搞不明白。。。


关于引用计数版本的垃圾回收机制,大家的说法都是:"无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0."


但是为什么不能检测出来呢?

比如

Class A

{

B b;

}

Class B

{

A a;

}


如果有以下代码:

{

A a = new A();    //假设分配了空间,地址为loc1,则loc1的引用计数为1;

B b = new B();    //假设分配了空间,地址为loc2,则loc2的引用计数为1;

a.b = b;          //loc2的引用计数为2;

b.a = a;          //loc1的引用计数为2;

}

变量a,b跳出作用范围之后,loc1和loc2的引用不会变成0吗?难道说,在对a进行处理时,不会将其成员b所引用的地址引用减1,同理,在处理变量b时,不会对其成员a所引用的地址减1,从而导致loc1和loc2的引用数目都为1?如果真的是这样的话,那不只是循环引用出问题,即使是没有循环引用也会出现问题的吧。比如:

Class A1

{

C1 c1;

}

Class C1

{


}


以下代码应用A1和C1:

{

A1 a1 = new A1();    //假设分配了空间,地址为loc1,则loc1的引用计数为1;

C1 c1 = new C1();    //假设分配了空间,地址为loc2,则loc2的引用计数为1;

a1.c1 = c1;          //loc2的引用计数为2

}

则变量a1,c1跳出作用域后,如果变量a1并不对其成员c1所引用的地址减1,那么loc2的地址引用计数不是1吗?这样不会引起内存泄露?


========== update: 以下还是不要看了。。。  A 中的 b 只是一个指针而已,不要对人家要求太多啊。。。========= 

所以我想,在变量跳出作用域后对其进行处理时,确实是要同时处理其成员的,而正是对其成员进行处理时,循环引用会导致一些问题。如果A和B互相引用,在a和b跳出作用域时,要处理a了,对其成员b引用的地址计数减1,要处理b了,对其成员a引用的地址计数减1,问题是既然处理顶层对象(偶表示用户自己定义的a和b)时需要考虑其成员引用的地址计数要减1,那么在对其成员进行处理时,应该也要遵循同样的规则,对成员的成员进行处理,我想这个时候就会造成无限的循环。

本来嘛,无限循环也没什么问题啊,就让计数变成0就不处理了嘛,但是关键是可能并非只有a引用b,很可能另外有c也引用b,那这个时候c还没有超出作用域但是b已经被垃圾回收了,那c不是悲剧了?


完全不知道理解的对不对,欢迎指正。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值