美文网首页iOS 学习历程ios专题面试整理
iOS学习心得之:MRC和ARC简单理解

iOS学习心得之:MRC和ARC简单理解

作者: 人话博客 | 来源:发表于2017-04-29 10:55 被阅读376次

    OC内存管理有两种模式:
    ARC automatic reference counting 自引用用计数
    MRC manual reference counting 手动引用计数

    在2011年、IOS5之前,OC的开发只支持MRC模式。
    也就是只支持手动引用计数。
    当时每当一个新的指针引用了一块堆空间(也就是对象)
    就必须手动的把此块堆空间内的 retainCount + 1。
    具体操作:

    Person* p = [Person new];//默认就是1 ,所以这里的p不需要手动操作。
    
    Person* p2 = p;
    [p2 retain];//将retainCount的值+1;
    
    当p2指针不使用此堆空间了。要手动把 retainCount 值 - 1
    [p2 release];
    
    p不用了,也需要release
    [p release];
    

    手动计数器使用规则:
    谁用谁retain,谁不用谁release。

    关于内存释放的本质:
    当一块内存释放的时候,本质上只是给这部分字节打了标签。并没有把字节里的二进制数据全部清成0或者1.
    所以,当一块内存说是释放了,但如果没有其他的二进制数据去填充它,那么它的内部数据是一直存在的。

    内存释放,数据仍然存在,就会出现一种僵尸对象的问题。
    什么是僵尸对象?堆空间已经被标记清空,能被其他数据使用。但此时此刻,新的二进制数据还没有进来。
    我们此时用一个指针指向已经标记释放了的堆空间。这个就叫僵尸对象和野指针。

        At mrc model:
        Person* p = [Person new];
        [p release];//指针指向的堆空间,在代码级别已经被释放。
        p.name = @“内存就没有释放的概念,只是打了可以被其他数据填充的标签”;
        NSLog(@“%@”,p.name);//但如果没有其他的数据填充这块空间,所以在某种条件下(没被其他数据填充)数据仍然存在。可以继续访问。
    

    关于dealloc函数释放堆空间。
    在手动模式下:
    1、可以直接调用dealloc 强制标记当前堆空间直接被释放,而不用去管retainCount是否是0.
    2、每次调用release 把 retainCount-1 的同时会判断retainCount的最终值是否是0,是0接着调用dealloc函数标记当前堆空间释放。

    如何在手动模式下,避免已经被标记的堆空间被指针引用并使用呢?
        因为被标记释放的堆空间,会在任意时间内被其他数据使用。所以这对这个指针来说是不安全的。
    有两种解决方式:
    1、打开僵尸对象检查机制【一但这块堆空间被标记释放了,那么所有的指针都不能使用这块空间】
    2、将你认为可能是指向僵尸堆空间的指针设置成nil
        OC的实例函数比较过硬,当传入的第一个参数,也就是self对象为nil时,函数也不会报错。
        这在.net里会爆出 【未将对象引用设置到对象实例】 的错误的。
    

    ARC:automatic reference counting 自动引用计数
    所有堆空间在新指针引用时的 retainCount+1 在指针不引用时 retainCount-1。
    自动维护引用计数,并标记释放当前堆空间。不需要程序员去关心。

    补充一点:
    当一块堆空间被标记可以删除之后,即使暂时没有新的数据填充这块空间。原来空间的数据也不能【复活】过来重新使用。
    eg:

    //引用计数1
    Person* p = [Person new];
    //引用计数jian-1,为0 触发dealloc。标记释放
    [p release];//
    [p retain];//此块堆空间已经被标记释放,所以对堆内的操作都将无效。数据马上就要被释放了,还操作个毛线。   

    相关文章

      网友评论

        本文标题:iOS学习心得之:MRC和ARC简单理解

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