美文网首页
OC基础-内存管理-MRC(五)

OC基础-内存管理-MRC(五)

作者: 浮华_du | 来源:发表于2021-08-30 10:18 被阅读0次

引用计数

引用计数(Reference counting)是一个简单有效管理对象生命周期的方式。
当我们新建一个新对象时候,它的引用计数+1,当一个新指针指向该对象,将引用计数+1。当指针不再指向这个对象时候,引用计数-1,当引用计数为0时,说明该对象不再被任何指针引用,将对象销毁,进而回收内存。


image.png

四条规则

  • 自己生成的对象自己持有 - alloc/new/copy/mutableCopy等方法
  • 非自己生成的对象,自己也能持有 - retain方法
  • 不再需要自己持有的对象时释放 - release方法(autorelease可以取得对象存在,但自己不持有对象,超出指定范围时能够自动并正确释放)
  • 不要释放非自己持有的对象,释放了会造成崩溃

1.自己生成的对象自己持有 -- alloc/new/copy/mutableCopy等方法

    id obj = [[NSObject alloc] init]; // 创建并持有对象,RC = 1
    NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)(obj)));
    //或    NSLog(@"retainCount = %ld",[obj retainCount]);
    // retainCount = 1
 id obj = [[NSObject alloc] init]; // 创建并持有对象,RC = 1
       /*
        * 使用该对象,RC = 1
        */
       [obj release]; // 在不需要使用的时候调用 release,RC = 0,对象被销毁
    NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)(obj)));
    //或    NSLog(@"retainCount = %ld",[obj retainCount]);
   // retainCount = 0

2.非自己生成的对象,自己也能持有 -- retain方法

使用上述方法以外的方法创建的对象,我们并不持有,其RC初始值也为 1。但是需要注意的是,如果要使用(持有)该对象,需要先进行retain,否则可能会导致程序Crash。原因是这些方法内部是给对象调用了autorelease方法,所以这些对象会被加入到自动释放池中。

(1).情况一:iOS 程序中不手动指定@autoreleasepool

当RunLoop迭代结束时,会自动给自动释放池中的对象调用release方法。所以如果我们在使用前不进行retain,那么当RunLoop迭代结束,对象就会收到release消息,如果此时该对象RC值降为 0 就会被销毁。而我们这时候再去访问已经被销毁的对象,程序就会Crash。

    /* 正确的用法 */

    id obj = [NSMutableArray array]; // 创建对象但并不持有,对象加入自动释放池,RC = 1

    [obj retain]; // 使用之前进行 retain,对对象进行持有,RC = 2
    /*
     * 使用该对象,RC = 2
     */
    [obj release]; // 在不需要使用的时候调用 release,RC = 1
    /*
     * RunLoop 可能在某一时刻迭代结束,给自动释放池中的对象调用 release,RC = 0,对象被销毁
     * 如果这时候 RunLoop 还未迭代结束,该对象还可以被访问,不过这是非常危险的,容易导致 Crash
     */
(2).手动指定@autoreleasepool

如果@autoreleasepool作用域结束,就会自动给autorelease对象调用release方法。如果这时候我们再访问该对象,程序就会Crash。

    /* 错误的用法 */
    id obj;
    @autoreleasepool {
        obj = [NSMutableArray array]; // 创建对象但并不持有,对象加入自动释放池,RC = 1
    } // @autoreleasepool 作用域结束,对象 release,RC = 0,对象被销毁
    NSLog(@"%@",obj); // EXC_BAD_ACCESS
    /* 正确的用法 */

    id obj;
    @autoreleasepool {
        obj = [NSMutableArray array]; // 创建对象但并不持有,对象加入自动释放池,RC = 1
        [obj retain]; // RC = 2
    } // @autoreleasepool 作用域结束,对象 release,RC = 1
    NSLog(@"%@",obj); // 正常访问
    /*
     * 使用该对象,RC = 1
     */
    [obj release]; // 在不需要使用的时候调用 release,RC = 0,对象被销毁
(3).自定义方法 创建但并不持有对象

方法名就不应该以 alloc/new/copy/mutableCopy 开头,且返回对象前应该要先通过autorelease方法将该对象加入自动释放池。

- (id)object
{
    id obj = [NSObject alloc] init];
    [obj autorelease];
    retain obj;
}

这样调用方在使用该方法创建对象的时候,通过方法名他就会知道他不持有该对象,于是他会在使用该对象前进行retain,并在不需要该对象时进行release。

备注:release和autorelease的区别:
  • 调用release,对象的RC会立即 -1;
  • 调用autorelease,对象的RC不会立即 -1,而是将对象添加进自动释放池,它会在一个恰当的时刻自动给对象调用release,所以autorelease相当于延迟了对象的释放。

3.不再需要自己持有的对象时释放

在不需要使用(持有)对象的时候,需要调用一下release或者autorelease方法进行释放(或者称为 “放弃对象使用权”),使其RC-1,防止内存泄漏。当对象的RC为 0 时,就会调用dealloc方法销毁对象。

4.不要释放非自己持有的对象

如果自己不是持有者,就不能对对象进行release,否则会导致程序Crash。另外,向已回收的对象发送消息也是不安全的.
持有对象的两种方式

  • 通过 alloc/new/copy/mutableCopy 等方法创建对象
  • 创建但并不持有的对象,通过retain方法持有
    id obj = [[NSObject alloc] init]; // 创建并持有对象,RC = 1
    [obj release]; // 如果自己是持有者,在不需要使用的时候调用 release,RC = 0
    /*
     * 此时对象已被销毁,不应该再对其进行访问
     */
    [obj release]; // EXC_BAD_ACCESS,这时候自己已经不是持有者,再 release 就会 Crash
    /*
     * 再次 release 已经销毁的对象(过度释放),或是访问已经销毁的对象都会导致崩溃
     */

    id obj = [NSMutableArray array]; // 创建对象,但并不持有对象,RC = 1
    [obj release]; // EXC_BAD_ACCESS 虽然对象的 RC = 1,但是这里并不持有对象,所以导致 Crash

执行如下代码,可能会有问题,也可能没有问题。对象所占内存在 “解除分配(deallocated)” 之后,只是放回可用内存池。如果对象所占内存还没有分配给别人,这时候访问没有问题,如果已经分配给了别人,再次访问就会崩溃。

    Person *person = [[Person alloc] init]; // 创建并持有对象,RC = 1
    [person release]; // 如果自己是持有者,在不需要使用的时候调用 release,RC = 0
    [person release]; // 向已回收的对象发送消息是不安全的

https://juejin.cn/post/6844904129676984334

相关文章

  • OC基础-内存管理-MRC(五)

    引用计数 引用计数(Reference counting)是一个简单有效管理对象生命周期的方式。当我们新建一个新对...

  • 《Effective Objective-C 2.0》读书笔记(

    第五章 内存管理 第29条:理解引用计数 OC 中有手动内存管理(MRC) 自动内存管理(ARC)手动内存管理需要...

  • iOS面试题-第一页

    1.简述OC中内存管理机制. 答:内存管理机制:使用引用计数管理,分为ARC和MRC,MRC需要程序员自己管理内存...

  • iOS面试 | 基础知识 | <1>

    1.简述OC中内存管理机制 答:内存管理机制:使用引用计数管理,分为ARC和MRC,MRC需要程序员自己管理内存,...

  • OC 知识:彻底理解 iOS 内存管理(MRC、ARC)

    OC 知识:彻底理解 iOS 内存管理(MRC、ARC) - 简书

  • iOS面试复习1——内存

    一、内存管理(MRC) (一) 管理对象 管理对象:OC对象 原因: 1、OC对象存放于堆里面 2...

  • OC中内存管理

    在OC中内存管理MRC手动内存管理和ARC自动内存管理,ARC是从iOS 4.0开始,在iOS 4.0之前...

  • 内存管理

    OC知识--彻底理解内存管理(MRC、ARC) IOS工程中混合使用ARC与MRC iOS 简单而粗暴的说一说内存...

  • iOS的内功:内存管理机制

    1.Objective-C的内存管理机制 OC的内存管理机制有三种,分别是ARC(自动内存管理),MRC(手动内存...

  • OC内存管理(MRC)

    OC内存管理(MRC) 后续更新 首先说明一下几块存储区域: 栈区(局部变量、函数参数值) 堆区(对象、手动申请...

网友评论

      本文标题:OC基础-内存管理-MRC(五)

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