美文网首页
Effective Objective-C 2.0读书笔记(5)

Effective Objective-C 2.0读书笔记(5)

作者: _桃夭大人_ | 来源:发表于2019-02-19 13:56 被阅读2次

    第五章 内存管理

    第二十九条:理解引用计数

    • 引用计数的原理


      image.png

      最终当保留计数归零时,对象就回收了,也就是说,系统会将其占用的内存标记为“可重用”,此时所有指向该对象是我引用也都变得无效了。

    一般调用完release之后都会清空指针,这样就能保证不会出现“悬挂指针”(指向无效对象的指针)。

    NSNumber * number = [[NSNumber alloc] initWithInt:123];
    [number release];
    number = nil;
    
    • 属性存取方法中的内存管理
      此方法将保留新值 并 释放旧值,然后跟新实例变量,令其指向新值。顺序很重要
    - (void)setFoo:(id)foo{
        [foo retain];
        [_foo release];
        _foo = foo;
    }
    

    *自动释放池
    autorelease 此方法会在稍后递减计数,通常是下一次“事件循环”时递减

    - (NSString *)stringVaule{
         NSString * str = [[NSString alloc] initWithFormat:@"haha"];
    return [str autorelease];
    // autorelease能延长对象生命周期,使其在跨越方法调用边界后 依然可以存活一段时间。
    }
    

    *保留环
    呈环状 相互引用的对个对象。导致内存泄漏。
    解决方法:
    (1)“弱引用”;
    (2)令循环中的某个对象不再保留另一个对象;

    • 引用计数机制 通过可以递增递减的计数器来管理内存。

    对象创建好之后,其保留计数至少为1,若保留计数为正,则对象存活,为0对象就被销毁了。

    • 在对象生命期中,其余对象通过引用来保留或者释放此对象。保留与释放操作分别会递增递减保留计数。

    第三十条 :以ARC 简化引用计数

    ARC会用一种安全的方式来设置:先保留新值,在释放旧值,最后设置啊实例变量。

    - (void)setup{
        id tmp = [EOCOtherClass new];
        _object = [tmp retain];
        [tmp release];
    }
    
    • 可以用修饰符来 改变局部变量与实例变量的语义:
    • __strong :默认语义,保留此值。
    • __unsafe_unretained: 不保留此值,这么做可能不安全,因为等到再次使用变量时,其对象可能已经回收了。
    • __weak: 不保留此值,但是变量可以安全的使用,因为如果系统把这个对象回收了,那么变量也会自动清空。
    • __autoreleasing: 把对象“按引用传递”给方法时,使用这个特殊的修饰符,此值在方法返回时自动释放。

    第三十一条:在dealloc方法中只释放引用并解除监听

    执行异步任务的方法不应该在dealloc里调用;只能在正常状态下执行的那些方法也不应该在dealloc里调用,因为此时对象已经处于正在回收的状态了。

    第三十二条:编写“异常安全代码”时留意内存管理问题

    • 在Objective-C代码中,只有当应用程序必须因异常状况而终止时才应抛出异常。因此还去添加 安全处理异常所用的附加代码是没有意义的。

    • 在默认情况下,ARC不生成安全处理异常所需要的清理代码,

    • 若要使用ARC且必须捕获异常,则需要打开编译器 -fobjc-arc-exceptions标志。开启后可生成这种代码,不过 会导致应用程序变大,而且会降低运行效率。

    第三十三条:以弱引用 避免保留环

    image.png

    第三十四条:以“自动释放池块”降低内存峰值

    Objective-C对象的生命周期取决于 其引用计数。
    释放对象的两种方式:
    (1)release 引用计数减一。
    (2)autorelease 在稍后某个时刻释放对象。

    // 创建自动释放池(轻量级)
    @autoreleasepool{
    // ... 
    }
    

    系统会自动创建一些线程,比如主线程和GCD机制中线程,这些线程默认都有自动释放池,每次执行“事件循环”时,就会将其清空。

    • 内存峰值:是指应用程序在某个特定的时段内的最大内存用量。新增的自动释放池块可以减少这个峰值,因为系统会在块的末尾把某些对象回收掉。

    • NSAutoreleasePool对象:专门用来表示自动释放池,通常用来创建那种偶尔需要清空的池。

    • 自动释放池排布在栈中,对象收到autorelease消息后,系统将其放入最顶端的池里。

    第三十五条:用“僵尸对象”调试内存管理问题

    向已经回收的对象发送消息是不安全的,取决于 对象所占内存有没有为其他内容所覆写。

    运行期系统会把所有已经回收的实例转化为特殊的“僵尸对象”,而且不会真正回收他们。
    “僵尸对象”所在的 核心内存 无法重用,因此不能覆写。僵尸对象收到消息后,会抛出异常。

    将 NSZombieEnabled环境变量 设为YES 开启“僵尸对象”功能。

    • 系统会修改对象的isa指针,令其指向特殊的僵尸类,从而使该对象变为僵尸对象。僵尸类能够响应所有的选择子,响应方式为:打印一条包含消息内容及其接收者的消息,然后终止应用程序。

    第三十六条:不要使用retainCount

    retainCount 是NSObject协议中定义的方法,用于查询对象当前的保留计数。ARC废弃了。
    此方法无用的原因:
    (1)它所返回的保留计数只是某个给定时间点上的值。未考虑到系统稍后会把自动释放池清空。
    (2)retainCount 可能永远不返回0,

    相关文章

      网友评论

          本文标题:Effective Objective-C 2.0读书笔记(5)

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