美文网首页
内存管理题

内存管理题

作者: 一个半吊子工程师 | 来源:发表于2020-10-30 17:20 被阅读0次

    1.管理原则

    1.1内存管理-黄金法则

    The basic rule to apply is everything that increases the reference counter with alloc, [mutable]copy[withZone:] or retain is in charge of the corresponding [auto]release.

    如果对一个对象使用了alloc、[mutable]copy、retain,那么你必须使用相应的release或者autorelease。

    1.2类型定义:

    基本类型:任何C的类型,如:int、short、char、long、struct、enum、union等属于基本类型或者结构体;

    内存管理对于C语言基本类型无效;

    任何继承与NSObject类的对象都属于OC类型。

    所有OC对象都有一个计数器,保留着当前被引用的数量。

    1.3内存管理对象:

    OC的对象:凡是继承于NSObject;

    每一个对象都有一个retainCount计数器。表示当前的被应用的计数。如果计数为0,那么就真正的释放这个对象。

    alloc、retain、release函数:

    1)alloc 函数是创建对象使用,创建完成后计数器为1;只用1次。

    2)retain是对一个对象的计数器+1;可以调用多次。

    3)release是对一个对象计数器-1;减到0对象就会从内存中释放。

    增加对象计数器的三种方式:

    1)当明确使用alloc方法来分配对象;

    2)当明确使用copy[WithZone:]或者mutableCopy[WithZone:]copy对象的时;

    3)当明确使用retain消息。

    上述三种方法使得计数器增加,那么就需要使用[auto]release来明确释放对象,也就是递减计数器。

    2. 非ARC模式,MRR(manual retain-release)

    MRR内存管理里的一个核心原则,“只负责你拥有的对象的生命周期”,也就是说,如果你对一个对象有所有权,那么你就要负责其回收的工作,否则,你不需要,也不能取回收你不拥有的对象。

    1:所有使用alloc, new, copy或mutabelCopy,以及这些关键词开头的函数返回的对象,你都是拥有所有权的,也就是要负责这些对象的内存回收工作。这是iOS开发中的一种约定,所以,当你编写自己的alloc, new或copy类型的函数时,也请遵循这样的命名规范。
    
    2:retain返回的对象,拥有所有权。例如显示调用retain函数返回的结果,或者synthesize 的retain类型的成员变量。
    
    3:所有使用其他函数返回的对象,没有所有权。
    
    4:返回的对象的引用,没有所有权。
    
    5:autorelease返回的对象没有所有权。
    

    2.1 cocoa中的内存管理机制——引用计数

    • 引用计数(reference counting)又称为保留计数(retain counting),引用计数的数值表示有几个其它对象在使用它。
    • 每一个对象都拥有一个引用计数
    • 当对象被创建的时候,引用计数的值为1 当发送retain消息的时候,该对象的引用计数加1,该对象的引用计数为2
    • 当这个对象发送release消息的时候,该对象的引用计数减1
    • 当一个对象的引用计数为0时,系统自动调用dealloc方法,销毁该对象。

    引用计数是实例对象的内存回收唯一参考
    引用计数(retainCount)是Objective-C管理对象引用的唯一依据。调用实例的release方法后,此属性减一,减到为零时对象的dealloc方法被自动调用,进行内存回收操作,也就是说我们永不该手动调用对象的dealloc方法。
    关于dealloc方法它的作用是,当对象的引用计数为0时,系统会自动调用dealloc方法,回收内存,它的一般写法为:

    
    -(void)dealloc
    {      
          [super  dealloc];
          [person release];                                                                                 
    }        
    

    在这里为什么要调用父类的dealloc方法呢?

    • 子类的某些实例是继承自父类的,因此,我们需要调用父类的dealloc方法,来释放父类拥有的这些对象。
      一般来说调用的顺序是,当子类的对象释放完时,然后再释放父类的所拥有的实例,这一点与调用初始化方法,正好相反。

    2.2 对象所有权

    当一个所有者(可以是任何一个OC对象)做了以下某个动作的时候,它就拥有了对一个对象的所有权。

    • 1,在OC中,对象不断的被其它创建、使用和销毁,为了保证程序不产生额外的内存开销,当对象不再被需要以后,应当被立即销毁。

    • 2,拥有对一个对象的使用权,我们称为是”拥有”这个对象。对象的拥有者个数至少为1,对象才得以存在,否则它应当被立即销毁。

    • 3,为了确定你(一个对象)何时具有对另外一个对象的所有权,以及明确对象所有者的权利和义务,Cocoa设立了一套标准。只有当你对一个对象做了alloc,copy和retain等操作之后,你才拥有它的所有权。当你不再需要这个对象的时候,你应该释放你对它的所有权。千万不要对你没有所有权的对象进行释放。

    //(1)如果创建或者复制某个对象时,则拥有了该对象的所有权,即包含下列关键词时:
    alloc,allocWithZone:,copy,copyWithZone:,mutableCopy,mutableCopyWithZone:
    
    //(2)如果没有创建或复制对象,而是保留引用,同样拥有该对象的使用权
     retain
    //(3)当拥有了某个对象的所有权,在不需要某一个对象时,需要释放他们,用
     release,autoRelease
    
    

    2.3 自动释放池的相关用法

    1)cocoa中的自动释放池(Autorelease pool),是能够自动释放赤忠的对象的。NSObject类提供了一个autorelease消息,当我们想一个对象发送autorelease消息的时候,这个对象就会随着释放池的销毁而释放。如果要向使用使用自动释放池释放对象,我们首先要有一个入池操作:

     //入池对象5.0之后的写法
    //创建自动释放池
    @autoreleasepool {
        //入池对象5.0之后的写法
     }
    
    //入池对象5.0之前写法
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    [pool release];
    
    

    自动释放池是以栈的形式实现的,当某个对象调用了autorelease方法时,该对象会被加入自动释放池的栈顶。对于发送了autorelease消息的对象,当自动释放池销毁时,自动释放池会对这些对象发送一条release消息,来释放他们。

    2)向自动释放池发送release及drain消息的区别
    当我们向自动释放池pool发送release消息时,它会向池中的每一个发送了autorelease消息的对象发送一条release消息,并且自身也会销毁。当向它发送drain消息时,只会释放里面吧的对象,而不会销毁自己。

    3. ARC模式

    当你在编译程序的时候提供自动管理内存的功能,它会自动加入内存的控制代码,控制对象的生命周期,大大简化了内存管理的步骤,ARC管理内容的原理就是,编译器会在适当的地方自动插入retain、release和autorelease消息

    3.1 ARC机制下有几个明显的标志:

    • 不允许调用对象的 release方法
    • 不允许调用 autorelease方法
    • 再重写父类的dealloc方法时,不能再调用 [super dealloc];

    3.2 ARC的注意点和优点

    • ARC的注意点

      • ARC是编译器特性,而不是运行时特性
      • ARC不是其它语言中的垃圾回收, 有着本质区别
    • ARC的优点

      • 完全消除了手动管理内存的烦琐, 让程序猿更加专注于app的业务
      • 基本上能够避免内存泄露
      • 有时还能更加快速,因为编译器还可以执行某些优化

    3.3 ARC的判断原则

    • ARC的判断原则

      • 只要还有一个强指针变量指向对象,对象就会保持在内存中
    • 强指针

      • 默认所有指针变量都是强指针
      • 被__strong修饰的指针
     Person *p1 = [[Person alloc] init];
     __strong  Person *p2 = [[Person alloc] init];
    
    
    • 弱指针
      • 被__weak修饰的指针
    __weak  Person *p = [[Person alloc] init];
    
    
    • 注意:当使用ARC的时候,暂时忘记“引用计数器”,因为判断标准变了。

    相关文章

      网友评论

          本文标题:内存管理题

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