Objective-C内存管理之-引用计数

本文会继续深刻学习OC内存管理,内容主要参考iOS高级编程,Objective-C基础教程,疯狂iOS讲义,是我学习内存管理的笔记objective-c

内存管理

1 内存管理的基本概念

1.1 Objective-C中的内存管理

  • 手动内存管理和自动释放池---MRC>(Mannul Reference Counting)
  • 自动内存管理---ARC>(Automatic Reference Count)
  • 自动垃圾回收---GC>(Garbage Collection)
因为iOS系统不支持垃圾回收,因此咱们在iOS开发中只能使用MRC和ARC来进行内存管理,本文再也不介绍Objective-C中的垃圾回收机制,可是此处注意Objective-C中是存在垃圾回收机制的

1.2 内存管理中存在的问题

  • 内存泄露:再也不须要的对象没有释放编程

    引发的问题:程序的内存占有量不断增长,最终会被耗尽致使程序崩溃
  • 野指针:没有进行初始化得指针函数

    引发的问题:浪费内存资源,若是调用程序会出现未知的结果,甚至致使程序崩溃学习

  • 悬空指针:一个指针指向一个被销毁的对象指针

    引发的问题:调用悬空指针指向的属性或者方法时,程序会出现未知的结果,甚至致使程序崩溃调试

  • 僵尸对象:过分释放的对象code

    引发的问题:对象

2.手动内存管理和自动释放池---MRC>(Mannul Reference Counting)

2.1 什么是引用计数(Reference Counting)

引用计数:Objective-C中引入了引用计数这一机制来跟踪并处理对象的生命周期,继承

管理方式:每一个对象都有一个与之关联的整数,这个整数被称为引用计数,在Objective-C中,经过不一样的方法能够对引用计数进行操做,具体的处理以下表:教程

对象操做 Objective-C方法 对应的操做结果
生成并持有对象 alloc, new, copy,mutableCopy等方法 生成对象并设置引用计数 =1
持有对象 reatain方法 使引用计数 +1
释放对象 release方法 使引用计数 -1
废弃对象 dealloc方法---系统自动调用 引用计数 =0 时调用

关于delloc方法:dealloc方法继承自NSObject,所以全部的对象都具备此方法,当一个对象的引用计数为0时,也就意味着没有任何程序须要此对象,系统会回收该对象所占用的内存,在系统销毁对象以前,会自动调用该对象的dealloc方法来执行一些回收操做,若是该对象还持有其余对象的引用,咱们必须重写dealloc方法来释放该对象引用的其余对象(一般就是使用该对象的release方法)

引用计数机制回收对象的说明:若是一个对象的引用计数为0,则代表程序已经再也不须要它,这时系统会自动回收该对象所占内存,相反,若是一个对象的引用计数不为0,系统就不该该回收,也不会回收它所占的内存

关于retainCount方法:Objective-C提供了retainCount方法来返回一个对象当前的引用计数

如何重写dealloc方法:

- (void)dealloc {

    // 处理该对象的其余引用(经过release方法)
    
    /** 回调父类的dealloc方法 */
    [super dealloc];
}

2.2 苹果如何管理引用计数

  • 2.2.1 由于NSObject类的源代码没有公开,咱们利用Xcode的调试器(lldb)和iOS大概追溯出其实现过程
    • alloc

      +alloc
      +allocWithZone: 
      class_createInstance        //此方法能够经过objc4中的runtime/objc-runtime-new.mm确认
      calloc                      // 分配内存块
    • retainCount

      -retainCount 
      __CFDoExternRefOperation    // 此函数根据retain,retainCount,release操做进行分发,调用__CFBasicHashXXX方法
      CFBasicHashGetCountOfKey
    • retain

      -retain
      __CFDoExternRefOperation 
      CFBasicHashAddValue
    • release

      -release 
      __CFDoExternRefOperation 
      CFBasicHashRemoveValue      // 当此函数返回0时, -release调用dealloc方法
  • 2.2.2 由__CFDoExternRefOperation函数以及此函数的调用关系,咱们大概推算苹果大概是使用散列表(引用计数表)来管理引用计数
    • 经过引用计数表来管理引用计数的好处:
      • 对象用内存块的分配无须考虑内存块头部
      • 引用计数表各记录中存有内存块的地址,可从各个记录追溯到各对象的内存块(在进行内存泄露的检查时,此条特性具备举足轻重的做用,即便出现故障致使对象占用的内存块损坏,可是只要引用计数表没有被破坏,咱们就能够肯定各内存块的位置,这就是设置全局断点能够查出哪里出现内存泄露的缘由)
        引用计数表

2.3 内存管理的思考方式

  1. 本身生成的对象,本身持有

    1.1 使用alloc new copy mutableCopy建立的对象只能本身持有

    id obj1 = [[NSObject alloc] init];
    id obj2 = [NSObject new];
    id obj3 = [NSObject copy];
    id obj4 = [NSObject mutableCopy];

    1.2 使用以上名称的开头的方法也意味着本身生成并持有对象

    allocNewObject

    newNewObject

    copyNewObject

    mutableCopyNewObject

  2. 非本身生成的对象,本身也能持有

    2.1 非alloc new copy mutableCopy生成的对象,变量obj自己不持有该对象

    id obj1 = [NSMutableArray array];
    id obj2 = [NSDictionary dictionary];

    2.2 经过retain方法,非经过alloc new copy mutableCopy生成的对象,能够成为本身持有的对象

    id obj = [NSMutableArray array];
    
    [obj retain];
  3. 再也不须要本身持有的对象时释放

    • 3.1 释放经过alloc new copy mutableCopy生成的对象,一旦不在须要,务必要使用release方法释放

      id obj = [[NSObject alloc] init];
      
      [obj release];
    • 3.2 用retain方法持有的非本身生成的对象,一旦再也不须要,也必定要使用release释放

      id obj = [NSMutableArray array];
      [obj retain];    // 经过retain方法持有对象
      [obj release];   // 在不须要时也要经过release方法释放对象
    • 3.3 用某个方法生成对象,并将其做为方法的返回值,这时咱们该如何处理

      • 3.3.1 经过alloc new copy mutableCopy 或其余符合命名规则的方法生成的对象,只须要原封不动的返回就能让调用方也持有该对象

        - (id)allocObject {
            id obj = [[NSObject alloc] init];
            return obj;
        }
        
        - (id)allocObjectWithObject:(id)obj {
            id object = [obj allocObject];
            return object;
        }
      • 3.3.2 若是持有非本身生成的对象,例如[NSMutableArray array]生成的对象,咱们要使用autorelease方法释放

        注:命名规则:用来取得谁都不持有的对象的方法名不能以alloc new copy mutableCopy开头

        - (id)object {  
             id obj = [NSMutableArray array];
             [obj autorelease];
             return obj;
        }
      • 3.3.3 autorelease方法:提供了这样的功能,使对象在超出指定的生存范围时自动并正确释放(调用release方法)
        release和autorelease的区别

  4. 非本身持有的对象没法释放---注意如下两点,若是发生这样的状况会致使程序崩溃

    • 4.1 经过alloc new copy mutableCopy方法或者经过retain方法持有的对象,一旦再也不须要时,必须进行释放,除此以外其余方法得到的对象绝对不能释放,一旦释放会形成程序崩溃

    • 4.2 本身持有的对象释放后再次释放,形成僵死对象,引发程序崩溃或在访问废弃的对象时崩溃

      id obj = [[NSObject alloc] init];
      [obj release]; 
      [obj release];   // 再次释放
相关文章
相关标签/搜索