zoukankan      html  css  js  c++  java
  • iOS内存管理系列之一:对象所有权与引用计数

    当一个所有者(owner,其本身可以是任何一个Objective-C对象)做了以下某个动作时,它拥有对一个对象的所有权(ownership):

    1. 创建一个对象。包括使用任何名称中包含“alloc”、“new”、或者“copy”的方法。

    2. 保留(retain)一个对象。

    一个对象可以有多个所有者,一个所有者也可以拥有多个对象。

    相应的,引用计数增减的基本规则是:

    1.当所有者创建一个对象时,该对象的引用计数为1。

    2.当所有者保留它时,该对象的引用计数加1。

    3.当所有者释放(release)它时,该对象的引用计数减1。

    与此相关的,当一个所有者对于一个对象的引用计数的增减总计为0时,它放弃了对这个对象的所有权。

    现在我们可以从两个不同的角度来看Objective-C的内存管理问题。从对象所有权的角度来看,当一个对象有着至少一个所有者(owner)的时候,它依然存在;当它没有任何所有者的时候,它会被释放掉。从引用计数的角度看,一个对象存在时,其引用计数大于零;当一个对象的引用计数为零时,它会调用dealloc方法并释放掉。这两个角度的关系是:在所有权的背后起作用的机制是引用计数机制;我们通过引用计数的增减来理解所有权的概念;但是你只应当使用所有权的概念来管理内存,因为如果你试图直接获取对象的引用计数,那么得到的数将让你感到匪夷所思——系统的一些框架会“偷偷”增减对象的引用计数。

    回顾一下,内存管理的目标是:

    当一个对象的某个所有者依然需要使用它时,保证这个对象的存在;当一个对象的所有所有者都不再需要它时,保证这个对象被销毁。因此只要任何一个所有者在使用完一个对象之后释放掉它,那么以上内存管理的目标就可以实现。

    我们可以得出任何一个所有者(记住,所有者本身也只是一个对象)所应当遵守的基本步骤:

    拥有一个对象 -> 使用一个对象 -> 放弃对象的所有权。

    从引用计数的角度来看就是:

    还需要这个对象时,保持对其增减为正;不再需要这个对象时,保持对其增减为0。

    下图很好地诠释了这些基本规则:所有者1和所有者2单独地执行了拥有对象、使用对象、放弃对象所有权的步骤;当所有者1不再需要该对象时及时放弃了所有权,但此时所有者2依然拥有该对象,因此该对象依然存在,所有者2可以继续使用它;当所有者2也不再需要该对象时,也放弃掉所有权,这时对象以不再有任何所有者(相应的引用计数也变为0),因此立刻被销毁掉。

    数计数的基本规则

    需要注意的是,所有者2只是复制了该对象的指针,并没有使用copy方法,因此复制指针这个操作本身并不增加对象的引用计数;而正因为所有者2希望能使用该对象,因此通过retain方法成为它的所有者,也保证了所有者1放弃该对象时,对象不被销毁。

     

    ===========附上评论==========

     

    1 | Hui

    February 13th, 2011 at 10:18 pm

     

    你画的这个图不对吧,右边这块owner应该先retain然后再让obj1指向这个对象吧。而且如果如果obj1不是nil, 应该先把原先的对象release掉吧。我也刚看到这里,无意中看到了你的Blog。

    2 | 老召

    February 16th, 2011 at 8:41 am

     

    兄弟,看你技术不错,有兴趣加入我们吗?

    我们是一家在上海的技术创业企业,目前主要做iphone/ipad/android上的游戏以及交互式展示应用开发(如3D动态电子出版物插页,移动AR增强现实应用)…… 具体的你可以去我们网站上看看。另外http://app.zealion.com是我们一些项目的sample展示。

    自由、激情是我们的风格,有兴趣的话可以保持联系,兼职,全职,乃至参股共同创业,我们都不排斥。

    3 | 雨雪霏霏

    March 13th, 2011 at 5:29 am

     

    @Hui: 感谢你的评论。这里为了介绍引用计数的增减,就没有涉及到obj1原先值的处理。 你说的是正确的,应当release掉原先的对象,但是在release之前还要做比较。对于所有者2来说,应当做: if (obj1 != obj) { [obj1 release]; obj1 = [obj retain]; }

    4 | Xie Wei

    May 22nd, 2011 at 2:33 am

     

    原来是自己画的图啊,厉害厉害!

    5 | cwang

    July 2nd, 2011 at 7:18 am

     

    是不是可以用autorelease延后释放,就不用比较了(比如在setter函数里面)

    将下述代码

    if (obj1 != obj) { [obj1 release]; obj1 = [obj retain]; }

    改为

    [obj1 autorelease]; [obj1 = [obj retain];

    也是可以的吧?

    6 | 雨雪霏霏

    July 11th, 2011 at 2:57 am

     

    cwang:感谢回帖!是的,使用autorelease会更简单明了。

    7 | 非藉秋风

    August 26th, 2011 at 4:51 am

     

    看到《Objective-C基础教程》上的处理方法也挺好: [obj retain]; [obj1 release]; obj1 = obj; 苹果建议在iPhone开发中尽量不用autorelease。

  • 相关阅读:
    Asp.net Mvc中MVCContrib中无法使用Castle的发解决方案
    Asp.net Mvc Framework 十(测试方法及Filter的示例)
    无注册表的COM调用
    Direct3D 9学习笔记(13)网格(Mesh)4
    Direct3D 9学习笔记(11)网格(Mesh)2
    ATL 核心COM继承类之IDispatchImpl及调用
    ATL 核心COM继承类之CComObjectRootEx及CComObjectLock
    Direct3D 9学习笔记(12)网格(Mesh)3
    ATL COM类之激活
    ATL 引用计数线程模型
  • 原文地址:https://www.cnblogs.com/wudan7/p/3554772.html
Copyright © 2011-2022 走看看