• 内存管理机制


    Objective-C中提供了两种内存管理机制MRC(MannulReference Counting)和ARC(Automatic Reference Counting),分别提供对内存的手动和自动管理,来满足不同的需求.

    ARC:

    ARC是Auto Reference Counting的缩写,即自动引用计数,由编译器在代码合适的位置中自动添加retain/Release/Autorelease/dealloc方法从而进行内存管理.

    ARC几个要点:

    • 在对象被创建时 retain count +1,在对象被release时 retain count -1.当retain count 为0 时,销毁对象。
    • 程序中加入autoreleasepool的对象会由系统自动加上autorelease方法,如果该对象引用计数为0,则销毁。

    那么ARC是为了解决什么问题诞生的呢?这个得追溯到MRC手动内存管理时代说起。

    MRC下内存管理的缺点:

    • 当我们要释放一个堆内存时,首先要确定指向这个堆空间的指针都被release了。(避免提前释放)
    • 释放指针指向的堆空间,首先要确定哪些指针指向同一个堆,这些指针只能释放一次。(MRC下即谁创建,谁释放,避免重复释放)
    • 模块化操作时,对象可能被多个模块创建和使用,不能确定最后由谁去释放。
    • 多线程操作时,不确定哪个线程最后使用完毕

     

    在ARC中与内存管理有关的标识符,可以分为变量标识符(_strong,  _weak, _unsafe_unretained, autoreleasing)和属性标识符(nonatomic/atomic, assign/retain/strong/weak/unsafe_unretained/copy,readonly/readwrite),对于变量默认为__strong,而对于属性默认为unsafe_unretained。也存在autoreleasepool。

     其中assign/retain/copy与MRC下property的标识符意义相同,strong类似与retain,assign类似于unsafe_unretained,strong/weak/unsafe_unretained与ARC下变量标识符意义相同,只是一个用于属性的标识,一个用于变量的标识(带两个下划短线__)。所列出的其他的标识符与MRC下意义相同。

    (1)对于assign,你可以对标量类型(如int)使用这个属性。你可以想象一个float,它不是一个对象,所以它不能retain、copy。

    (2)对于copy,指定应该使用对象的副本(深度复制),前一个值发送一条release消息。基本上像retain,但是没有增加引用计数,是分配一块新的内存来放置它。特别适用于NSString,如果你不想改变现有的,就用这个,因为NSMutableString,也是NSString。

     

    MRC:

    在MRC的内存管理模式下,与对变量的管理相关的方法有:retain,release和autorelease。retain和release方法操作的是引用记数,当引用记数为零时,便自动释放内存。并且可以用NSAutoreleasePool对象,对加入自动释放池(autorelease调用)的变量进行管理,当drain时回收内存。

    Strong 和 Weak 的区别:

    强引用持有对象,弱引用不持有对象。 

    强引用可以释放对象,但弱引用不可以,因为弱引用不持有对象,当弱引用指向一个强引用所持有的对象时,当强引用将对象释放掉后,弱引用会自动的被赋值为nil,即弱引用会自动的指向nil。

    Strong 强引用,举个例子:

    1 id __strong test0 = [[NSObject alloc] init]; /* 设为对象A*2 
    3 id __strong test1 = [[NSObject alloc] init];/*设为对象B*/

    test0 和 test1 都是强引用,test0是对象A的持有者,就是拥有A,test1是对象B的持有者,就是拥有对象B,若:

    test1 = test0;/*对象A的持有者就变成了test1*/

    这样对象B就没有了持有者,没有持有者的对象会被ARC回收,就是释放,这样:

    test1持有对象A,test0也持有对象A。

    weak 弱引用,主要作用是用来防治循环引用出现内存泄漏的问题,它主要是弱引用,弱引用就是不持有对象,只是指向这个对象,举个例子:

    1 id __strong test0 = [[NSObject alloc] init]; /* 设为对象A*2 
    3 id __strong test1 = [[NSObject alloc] init];/*设为对象B*4 
    5 id __weak test2 = test0;/*test1持有对象A的弱引用*/

    test0持有对象A的强引用,而test2持有对象A的弱引用,也就是说,test0还是持有A的,而test2弱引用了test0的对象A,并没有持有对象A,当test2离开了作用域,对对象A的引用就会失去,当对象A被释放掉之后,test2会被置为nil,并不会出现crash。若:

    test1 = test0;/*test1强引用对象A*/

    此时对象B因为没有持有者就会被释放。

    再如:

     1 #import <Foundation/Foundation.h>
     2 
     3 int main(int argc, const char * argv[]) {
     4     @autoreleasepool {
     5         id __weak obj0 = nil;
     6         if (YES) {
     7             id obj1 = [[NSObject alloc] init];  //默认为强引用,即为strong类型
     8             obj0 = obj1;
     9             NSLog(@"obj0: %@", obj0);
    10         }
    11         NSLog(@"obj0: %@", obj0);
    12     }
    13     return 0;
    14 }
    15 
    16 /*
    17  *  输出结果
    18  *  obj0: <NSObject: 0x1003066c0>
    19  *  obj0: (null)
    20  *
    21  *  因为obj1生成的默认的为强引用(__strong),在超出if的作用域之后,obj1所持有的对象被释放,
    22  *  obj0为弱引用,所以obj0不持有对象,在obj1对象释放后,obj0自动的被赋值为nil
    23  *  弱引用的特性是,不持有对象,即便是写成id __weak obj1 = [[NSObject alloc] init];
    24  *  此代码系统会给与警告,因为这里obj1被声明成弱引用,那么在赋值之后,alloc出来的对象会被立即释放。
    25  */
  • 相关阅读:
    BZOJ1054|HAOI2008移动玩具|广搜
    tarjan算法
    BJOJ2190|SDOI仪仗队|数论
    POJ2975|Nim|博弈论
    POJ1740|A NEW STONE GAME|博弈论
    python 单例模式
    linux 根据服务名称批量杀死进程
    python 任务计划
    python偏函数
    安装scrapy框架
  • 原文地址:https://www.cnblogs.com/EchoHG/p/7118888.html
Copyright © 2020-2023  润新知