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放弃该对象时,对象不被销毁。

    自动释放与便捷方法(转)

    有时候一个所有者创建一个对象后,会立刻将该对象的指针传递给其它所有者。这时,这个创建者不希望再拥有这个对象,但如果立刻给它发送一个 release消息会导致这个对象被立刻释放掉——这样其它所有者还没有来得及保留该对象。解决这个两难问题的方法是,给对象发送一个 autorelease消息:这样创建者不再拥有该对象的所有权;该对象成为自动释放的对象,但是不会立刻被释放掉;其它所有者可以有时间保留或复制该对 象,并成为其唯一所有者。

    我们来看一个自动释放的例子(代码清单3-1)。一个所有者先用alloc方法创建一个对象;此时 该所有者拥有这个对象,对象的引用计数为1。紧接着,所有者自动释放该对象;所有者此时已经放弃了所有权,但对象的引用计数在一段时间内依然为1。我们可 以看出自动释放的另一个好处:你不会因为在后面忘记给对象发送release消息而造成内存泄露。

    代码清单3-1

    -(Object*)returnAutoreleaseObject {

    Object* obj = [[Object alloc] init];

    return [obj autorelease];

    }

    与自动释放相关的,有一大类构造方法(constructor method),由它们构造的对象直接就是自动释放的对象;这一类构造方法叫做便捷方法。比如下面这句的字符串就是一个自动释放的对象,stringWithFormat:就是一个便捷方法。

    NSString* string = [NSString stringWithFormat:@”autoreleaseString”];

    再举几个便捷方法的例子,方便读者以后的开发。

    1.NSArray的arrayWithObjects:和arrayWithArray:。

    2.UIImage的imageNamed:。

    3.NSNumber的numberWithBool等。

    现在我们已经解释了,autorelease方法会在一段时间以后释放掉一个对象,在这段时间内我们可以安全地使用该对象。那么这段时间究竟是多久呢?我们需要先更多地了解自动释放的机制,再来回答这个问题。

    让 我们先来看看自动释放池。自动释放池是NSAutoreleasePool的实例,其中包含了收到autorelease消息的对象。当一个自动释放池自 身被销毁(dealloc)时,它会给池中每一个对象发送一个release消息(如果你给一个对象多次发送autorelease消息,那么当自动释放 池销毁时,这个对象也会收到同样数目的release消息)。可以看出,一个自动释放的对象,它至少能够存活到自动释放池销毁的时候。

    那么 自动释放池何时被创建,又何时被销毁呢?在每一个事件周期(event cycle)的开始,系统会自动创建一个自动释放池;在每一个事件周期的结尾,系统会自动销毁这个自动释放池。一般情况下,你可以理解为:当你的代码在持 续运行时,自动释放池是不会被销毁的,这段时间内你也可以安全地使用自动释放的对象;当你的代码运行告一段落,开始等待用户输入(或者其它事件)时,自动 释放池就会被释放掉,池中的对象都会收到一个release消息,有的可能会因此被销毁。

    到此为止,相信你已经对自动释放的机制有了一个大 体的了解。自动释放而非直接释放,可以帮助你节省一些代码量,提高开发速度。但是它有一个直接的缺点:它延缓了对象的释放,在有大量自动释放的对象时,会 占用大量内存资源。因此,你需要避免将大量对象自动释放。并且,在以下两种情况下,你需要手动建立并手动销毁掉自动释放池:

    1.当你在主线程外开启其它线程时:系统只会在主线程中自动生成并销毁掉自动释放池。

    2.当你在短时间内制造了大量自动释放对象时:及时地销毁有助于有效利用iPad上有限地内存资源。

  • 相关阅读:
    Open source cryptocurrency exchange
    Salted Password Hashing
    95. Unique Binary Search Trees II
    714. Best Time to Buy and Sell Stock with Transaction Fee
    680. Valid Palindrome II
    Java compiler level does not match the version of the installed Java project facet.
    eclipse自动编译
    Exception in thread "main" java.lang.StackOverflowError(栈溢出)
    博客背景美化——动态雪花飘落
    java九九乘法表
  • 原文地址:https://www.cnblogs.com/mcj-coding/p/3556207.html
Copyright © 2011-2022 走看看