如何解决引用计数的循环引用问题

循环引用

public class MyObject {
    public Object ref = null;
    public static void main(String[] args) {
        MyObject myObject1 = new MyObject();
        MyObject myObject2 = new MyObject();
        myObject1.ref = myObject2;
        myObject2.ref = myObject1;
        myObject1 = null;
        myObject2 = null;
    }
}

在这里插入图片描述
上图为例,当代码执行完line7时,两个对象的引用计数均为2。此时将myObject1和myObject2分别置为null,以前一个对象为例,它的引用计数将减1。

若要满足垃圾回收的条件,需要清除myObject2中的ref这个引用,而要清除掉这个引用的前提条件是myObject2引用的对象被回收,可是该对象的引用计数也为1,因为myObject1.ref指向了它。以此类推,也就进入一种死循环的状态。

JVM :

通过可达性分析解决。

还有一种方式就是利用工具在编译之前进行判断,做一个限制。如果出现循环应用停止编译等等。

C++ :

为避免这个问题,c++中会将互相引用的两个对象中,其中一个引用 weak_ptr,
因为 weak_ptr 不会使引用计数加1,所以就不会出现这种互相拖着对方的事情了。

Redis :

但熟悉JVM的都知道,引用计数他有一种缺陷就是,解决不了循环引用的问题。但Redis不知道为啥不存在这个问题?

因为redis对象之间没有深层次的嵌套,因此也就不存在循环引用的隐患。这个地方要好好看看redis对象结构,才能理解。

纵观redis的对象,发现他们用不同的数据结构来实现,所以顶多有一个指向底层的实现数据结构的指针,既然redis对象里面不可以再定义一个别的引用,那么久不会出现循环引用的问题了,因为redis只共享0-9999的数值字符串对象,对于别的对象,ptr指针是不会去寻找是否有相同的,然后指向,所以不存在循环引用。

typedef struct redisObject {  
  
// 类型  
unsigned type:4;  
  
// 编码  
unsigned encoding:4;  
  
// 指向底层实现数据结构的指针  
void *ptr;  
  
// 引用计数
int refCount
// ...  

} robj;  

因为c语言不具有自动回收的功能,所以Redis在自己的对象系统中构建了一个引用计数实现内存回收机制。

  • 在创建一个对象时,引用计数初始化为。
  • 当对象被一个新程序使用时,+1;
  • 当对象不再被一个程序使用时,-1;
  • 为0时代表可以回收了。

因为是否共享需要判断两个对象是否相同。

除了用于实现引用计数内存回收机制之外,对象的引用计数还带有对象共享的作用

Redis对整数 0-9999(共1W个整数)做了缓存。类似于Java对-128-127做缓存一样。

如果共享对象是保存字符串值的字符串对象,如aaaaa的这种缓存,毕竟判断一个字符串是否在库里面,需要扫整个库,时间复杂度为O(N),非常耗时,并且cpu压力非常的大。

如果共享对象是包含了多个值(或者对象的)的对象,比如列表对象或者哈希对象,验证操作复杂度O(N2);

因此,redis只对包含数值的字符串对象进行共享。

处于优化,折中的考虑,也就缓存了0-9999吧。其实看看淘宝商品的价格,缓存0-100足矣,毕竟0-100占据了99%的商品。

总结

  1. 第一个方法是我明确知道这里会存在循环引用,在合适的位置主动断开环中的一个引用,让对象得到回收
  2. 第二个方式弱引用 :例如我们在ARC中的delegate,block
  3. 使用xcode检测循环引用
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值