iOS 循环引用问题解决方案

一:循环引用

       循环引用:是指两个对象相互retain对方,通过OBJC的release是无法销毁这两个对象的。更严重的是,如果几个对象间接相互引用:比如A<-B,B<-C,C<-A,那么A、                   B、C都无法通过release释放;举例说明:

• 对象a创建并引用到了对象b.
• 对象b创建并引用到了对象c.
• 对象c创建并引用到了对象b.

这时候b和c的引用计数分别是2和1。当a不再使用b,调用release释放对b的所有权,因为c还引用了b,所以b的引用计数为1,b不会被 释放。b不释放,c的引用计数就是1,c也不会被释放。从此,b和c永远留在内存中这种情况,必须打断循环引用,通过其他规则来维护 引用关系。
引用链条中只要有一环发生循环引用,就会导致内存泄露。工具难以查出,因为符合使用约定 遗憾的是相互引用十分常见,对于界面来说有时 是必要的,特别是OBJC大量使用委托模式进行回调。因此 OBJC也建议委托最好不进行retain,而改用 assign,以避免循环引用 。不过一些 异步调用   多线程使用 是很难通过此种方式解决的, 容易出现野指针 。所以要解决循环引用导致的内存泄露需要从根源理 解泄露出现的原因,而不是单纯禁止 使用。
循环引用问题,是引用计数所引入的问题。因此使用引用计数作为数据管理的 架构 都会出现类似问题。 Java 、C#的垃圾回收机制都有专门的
来解 决此问题。引数管理的数据都是共享关系,相互引用就是相互共享,这种内存泄露是符合共享逻辑的。但实际情况中, 当出现相互引用,往
往存在依 赖关系 。一个引用为拥有,而另一个仅为回调。 回调引用依赖拥有引用 引数管理不能直接描述 依赖 关系,因此需要手工打断。
解决上面的循环引用问题:现假设b处由于某种原因使c被释放掉,比如线程结束或是Cancel操作,则此时在由root处释放a时,则全部释放。
以不 是只要循环引用就会内存泄露,通过 打断 解决内存泄露 是有效的,因为 打断补充了相互引用的依赖逻辑 。但要注意,如果出于省事仅将打断代
码放置 在dealloc中,则仍然会出现内存泄露。 原因在于release字面意思是释放的意思,但这里的释放不是内存的最终释放而是 所有权的释放 。调用
 release是分不清内存释放还是仅仅减了一个计数。循环引用时, 存在于dealloc中的打断代码,将永远不会通过release调用 。因此要解决循环引用,还

 要注意不要将打断代码放置在 dealloc中,而要在使用完毕后立即打断,dealloc的打断只能作为象征性防护

总结:

防止循环引用导致的内存泄露,基本上有两种方法。

1)如果其中一个对象的生命周期覆盖另一个对象,则采用OBJC推荐的策略,短周期对象保持长周期对象使用assign

2)如果相互引用的对象其生命周期不能覆盖对方,则必须在各自生命周期的终点处打断对方,打断代码不能依赖在dealloc时打断。比如对于UI

对象可通过事件处打断,线程对象于Main结尾处打断。只要有一处打断被执行就不会产生内存泄露。

此外还有另一种解决方法——利用指针的指针建立依赖引用机制

这里提供一下思路:引用双方只assign不retain,双方再额外存储对方引用的指针,当一方release时顺便将自身在对方的引用清空,以达到通知连

 接断开的目的。可将这种引用关系封装为一个类简化使用。

优点:避免循环引用导致内存泄露,即便在release处释放连接也不会引起内存泄露。

缺点:引用返回的是id类型,因此使用时需要类型转换。

另外编程时还要注意非预期的循环引用。比如OBJC库中经常使用字典作为参数的保存位置,而字典使用retain保存对象。如果A保持字典,字典中

 又保持A,或者保持B,但B保持A,则有可能产生内存泄露。

总之循环引用引起内存泄露,是需要在OBJC中额外注意的。C/C++不会产生此问题,因为引用需要手工维护。JAVA、C#中由于垃圾回收机制,

 也无需刻意注意。


备注:内存释放(当引用计数为0时进行的操作)和所有权释放(引用计数减一)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值