OC的内存管理

作者: 一个人在路上走下去 | 来源:发表于2016-06-15 21:31 被阅读1208次

    内存管理四句箴言:

    自己生成的自己持有
    非自己生成的对象自己也可持有
    不再需要自己持有时释放
    非自己持有的对象无法释放

    Objective-C中的内存管理机制跟C语言中指针的内容是同样重要的,要开发一个程序并不难,但是优秀的程序则更测重于内存管理,它们往往占用内存更少,运行更加流畅。在Xcode4.2及之后的版本中由于引入了ARC(Automatic Reference Counting)机制,程序编译时Xcode可以自动给你的代码添加内存释放代码。内存管理是开发中不可忽略的一块,虽然ARC帮我们节省了很多精力,不过作为一名合格的开发人员,最基本的知识还是要理解的。

    自持与不自持

    在开发中,如果使用了alloc,new,copy,mutableCopy或以其开头的方法名,意味着自己生成的对象只有自己持有,如:allocMyJob,newItName,copyAfter,mutableCopyYourName。但是以allocate,newer,copying,mutableCopyed开头的是不自己持有的,很明显它们是假冒的。

    以下为例:

     id obj = [NSMutableArray array]; // 取得非自己生成并持有的对象
    

    取得的对象存在,但自己并不持有对象。NSMutableArray类对象被赋给变量obj,但变量obj自己并不持有该对象。持有时需要用retain方法,如:

    id obj = [NSMutableArray array]; 
    [obj retain];
    

    通过retain,非自己用alloc等生成的对象也可以自己持有了。

    不需要时,使用release释放,对象一经释放就不可访问了。用alloc/new/copy/mutableCopy持有和retain持有的对象,不需要时一定要用release释放。

    同理使用如allocObject也可以取得自己持有对象。

    id obj1 = [obj0 allocObject];
    

    当使用autorelease时,即是取得了对象存在,但是自己不持有对象。如:

    - (id)object
    {
    id obj = [[NSObject alloc] init]; //自己持有对象
    [obj autorelease];
    return obj;// 取得的对象存在,但自己不持有
    }
    
    autorelease

    autorelease

    [NSMutableArray array]就是因为用了autorelease使得谁都不持有的。当然再次使用retain就持有了。程序里的所有autorelease pool是以桟(stack)的形式组织的。新创建的pool位于桟的最顶端。当发送autorelease消息给一个对象时,这个对象被加到栈顶的那个pool中。发送drain给一个pool时,这个pool里所有对象都会受到release消息,而且如果这个pool不是位于栈顶,那么位于这个pool“上端”的所有pool也会受到drain消息。

    [pool drain] 和 [pool release] 的区别:
    release,在引用计数环境下,由于NSAutoReleasePool是一个不可以被retain的类型,所以release会直接dealloc pool对象。当pool被dealloc的时候,pool向所有在pool中的对象发出一个release的消息,如果一个对象在这个pool中autorelease了多次,pool对这个对象的每一次autorelease都会release。在GC(garbage-collected environment)环境下release是一个no-op操作(代表没有操作,是一个占据进行很少的空间但是指出没有操作的计算机指令)。

    drain,在引用计数环境下,它的行为和release是一样的。在GC的环境下,这个方法调用objc_collect_if_needed 触发GC。重点是:在GC环境下,release是一个no-op,所以除非你不希望在GC环境下触发GC,你都应该使用drain而不是使用release来释放pool。原文如下:

    drain

    In a reference-counted environment, releases and pops the receiver; in a garbage-collected environment, triggers garbage collection if the memory allocated since the last collection is greater than the current threshold. - (void)drain

    Discussion
    **In a reference-counted environment, this method behaves the same as release. **Since an autorelease pool cannot be retained (see retain
    ), this therefore causes the receiver to be deallocated. When an autorelease pool is deallocated, it sends a release message to all its autoreleased objects. If an object is added several times to the same pool, when the pool is deallocated it receives a release message for each time it was added.In a garbage-collected environment, this method ultimately calls objc_collect_if_needed.

    Special Considerations
    In a garbage-collected environment, release is a no-op, so unless you do not want to give the collector a hint it is important to use drain in any code that may be compiled for a garbage-collected environment.

    对于iOS来说drain和release的作用其实是一样的。

    一个对象被加到一个pool很多次,只要多次发送autorelease消息给这个对象就可以;同时,当这个pool被回收时,这个对象也会收到同样多次release消息。简单地可以认为接收autorelease消息等同于:接收一个retain消息,同时加入到一个pool里;这个pool用来存放这些暂缓回收的对象;一旦这个pool被回收(drain),那么pool里面的对象会收到同样次数的release消息。-UIKit框架已经帮你自动创建一个autorelease pool。大部分时候,你可以直接使用这个pool,不必自己创建;所以你给一个对象发送autorelease消息,那么这个对象会加到这个UIKit自动创建的pool里。

    某些时候,可能需要创建一个pool:
    1.没有使用UIKit框架或者其它内含autorelease pool的框架,那么要使用pool,就要自己创建。

    2.如果一个循环体要创建大量的临时变量,那么创建自己的pool可以减少程序占用的内存峰值。(如果使用UIKit的pool,那么这些临时变量可能一直在这个pool里,只要这个pool受到drain消息;完全不使用autorelease pool应该也是可以的,可能只是要发一些release消息给这些临时变量,所以使用autorelease pool还是方便一些)

    3.创建线程时必须创建这个线程自己的autorelease pool。-使用alloc和init消息来创建pool,发送drain消息则表示这个pool不再使用。pool的创建和drain要在同一上下文中,比如循环体内。

    结语

    ObjC中没有垃圾回收机制,在ObjC中内存的管理是依赖对象引用计数器来进行的:在ObjC中每个对象内部都有一个与之对应的整数(retainCount),叫“引用计数器”,当一个对象在创建之后它的引用计数器为1,当调用这个对象的alloc、retain、new、copy方法之后引用计数器自动在原来的基础上加1(OC中调用一个对象的方法就是给这个对象发送一个消息),当调用这个对象的release方法之后它的引用计数器减1,如果一个对象的引用计数器为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象。手动管理内存有时候并不容易,因为对象的引用有时候是错综复杂的,对象之间可能互相交叉引用,此时需要遵循一个法则:谁创建,谁释放

    相关文章

      网友评论

      本文标题:OC的内存管理

      本文链接:https://www.haomeiwen.com/subject/eympdttx.html