04内存管理

4.1 手动管理

  • 自己生成的对象自己持有,可以调用release方法减少retain数量。
  • 非自己生成的对象也可以持有,通过调用retain方法可以持有对象,引用数+1。
  • 不再需要自己持有的对象要及时释放,注意类中的property要在- (void)dealloc方法中赋值nil,这样写相当于release了。
- (void)dealloc
{
    self.arr = nil;
    [super dealloc];
}
  • 无法释放非自己持有的对象,注意当一个变量持有一次对象后,只能释放一次。也就是说retainCount必须+1和-1对称。

  • alloc的实现。其实就是调用calloc方法申请内存和C语言的差不多,只不过对象的头部位有个地址用于存储引用数。而retain、release就是对引用数加减,dealloc则是free掉对象。

4.2 Autorelease

  • autorelease这个玩意本质上是将对象加入到最近的一个NSAutoreleasePool中,当NSAutoreleasePool销毁时会将对象release。因此这里就有个坑了,如果这个pool很久都不销毁,里面的对象就始终存在,有可能会造成内存不足。
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

// 当调用autorelease方法时,其实是将对象obj放到了pool的一个对象列表中
NSObject* obj = [[[NSObject alloc] init] autorelease];

[pool drain]; // obj会被调用release方法

  • 注意到main.m中有这样的代码,在最外层就有个autoreleasepool了。
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

4.3 ARC

  • 我的理解

所谓ARC是通过编译器和运行时的协作来实现自动管理引用计数,编译器在ARC有效的代码中加入额外的代码来加减引用计数。

  • 标识

    1. __strong:默认就是
    2. __weak:需显式使用
    3. __autoreleasing:这个标识一些情况下是不需要显式使用,一些情况下是不需要的,最为致命。
    4. __unsafe_unretained:个人感觉已经被弃用了,在没有weak的时代使用的东西。
  • __strong

这个修饰符具有持有对象的功能,与retain类似。它的使用分为如下几种情况:
1、id __strong obj = [[NSObject alloc] init]; 这行代码可以理解为如下代码,可见所谓自动管理,就是在编译出来的代码中对强引用变量调用release方法。

id obj = objc_msgSend(NSObject, @selector(alloc));

objc_msgSend(obj, @selector(init));
objc_release(obj);


2、`id __strong obj = [NSMutableArray array];` 这行代码可以理解为以下代码,很有意思的代码。objc_retainAutoreleasedReturnValue是持有(retain)了一个在autoreleasepool中的对象,而这个对象就是array方法的返回值。

id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj); // 离开作用域后自动释放


与`objc_retainAutoreleasedReturnValue`成对出现的是这个方法`objc_autoreleasedReturnValue`方法,对于NSMutableArray类的array方法可能是这样实现的
  • (id)array
    {
    return [[NSMutableArray alloc] init];
    }

它可以理解为如下代码

  • (id)array
    {
    id obj = objc_msgSend(NSMutableArray, @selector(alloc));
    objc_msgSend(obj, @selector(init));
    return objc_autoreleasedReturnValue(obj);
    }

<font color=green>对于外界调用这个方法赋值的变量来说,只是在使用一个autoreleasepool中的对象。在结合`objc_retainAutoreleasedReturnValue`使用时,其实生成的对象并没有进入autoreleasepool,而是直接传递给了使用`objc_retainAutoreleasedReturnValue`方法赋值的变量。</font>
  • __weak

    1、被__weak修饰的<font color=green>变量的地址</font>会被放入到weak表中,这个表是个k-v形式的,key是对象的地址,value是所有引用了这个对象的变量的地址。

    2、一个对象被释放的过程是个复杂的过程,

    objc_release -> dealloc(如果引用计数为0) -> _objc_rootDealloc 
    -> object_dispose -> objc_destructInstance 
    -> objc_clear_deallocating
    {
      1、用对象地址找到weak表中的value
      2、所有变量(weak表中记录了地址)赋值nil
      3、从weak表删除记录
      4、从引用计数表删除废弃对象的地址为键值的记录
    } 
    
    从以上的过程可以看出当对象被销毁后所有引用它的__weak变量都会被赋值为nil,这个过程是比较消耗CPU的,少用。
    
    3、<font color=green>**使用被__weak修饰的变量就是使用注册到autoreleasepool中的对象**</font>,从以下代码来进行理解这句话,
    
    id __weak obj1 = obj;
    NSLog(@"%@", obj1);
    
    这句话会大致被编译器翻译成这样
    

    id obj;
    objc_initWeak(&obj1, obj);
    id tmp = objc_loadWeakRetaind(&obj1);
    objc_autorelease(tmp);
    NSLog(@"%@", tmp);
    objc_destroyWeak(&obj1);

    可以看到为了能够NSLog执行时obj1引用的对象不被销毁,需要将它赋值给一个strong(默认)修饰的临时变量,而这个临时变量需要放到autoreleasepool中,因此存在一个问题,当你多次在一个作用域中多次使用weak修饰的变量,会导致很多临时变量产生而且会放到autoreleasepool中,作用域结束后autoreleasepool有很多工作要做。所以少用weak,一般就是避免循环引用。

  • __autoreleasing,核心就是把修饰的变量放入到autoreleasepool中,没啥多说的。

  • 注意事项:

    1. 不能使用retain、release、retainCount、autorelease这样方法
    2. 不能使用NSAllocateObject和NSDeallocateObject方法,实际上我根本没用过。
    3. 需要在函数命名时遵守规则,比如alloc\new\copy\mutableCopy必须给与调用者对象持有权限。
    4. 不能使用NSAutoreleasePool,可以用@autoreleasepool替换。
    5. dealloc方法不能显示调用,很明显的例子就是在MRC中写dealloc方法时一定要调用super的dealloc方法,但是在ARC中不行了,不过notificationCenter的删除等处理还是要写在dealloc方法中的,会自动调用。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容