iOS内存管理机制解析之MRC手动引用计数机制

Posted 欣麒骥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS内存管理机制解析之MRC手动引用计数机制相关的知识,希望对你有一定的参考价值。

前言:

ios的内存管理机制ARC和MRC是程序员参加面试基本必问的问题,也是考察一个iOS基本功是
否扎实的关键,这样深入理解内存管理机制的重要性就不言而喻了。

iOS内存管理机制发展史

  • iOS 5以前 :MRC(手动引用计数)

  • iOS 5及以后:ARC (自动引入计数)


MRC机制时代

“谁开辟申请,谁及时合理释放” 面对自己申请的内存空间是要及时进行回收的:

不及时释放会造成什么结果?

对象存储在栈上,可能会大量的占用内存,内存不足造成程序闪退(也就是所说的内存泄露)

不合理释放会造成什么后果?

提前释放掉,倘若后面继续对该对象进行引用操作,会出现崩溃,出现EXC_BAD_ACCESS操作已经释放掉的对象的崩溃提示。(也就是所说的野指针)

MRC机制时代对于iOS程序员来说是有些痛苦的,那么我们深入的解析一下

内存管理原则 —-配对原则

解释:使引用计数(retainCount)+1的时候必须相对应的出现使引用计数-1

怎样使引用计数+1 ?

new copy(mutablecopy) retain alloc

怎样使引用计数-1?

release autorelease

例如:

[对象 release];  reatinCount-1

[对象 retain];   reatinCount+1,并且返回self

判断一个对象是否能被系统回收?

正藏情况下能被系统回收的对象唯一依据是该对象的引用计数(retainCount)为0

再谈谈dealloc函数

     //当实例变量的引用计数为0,系统会自动调用dealloc函数进行摧毁回收
     - (void)dealloc  

重写dealloc函数时应注意:

  1. 重写dealloc时需要对用父类的dealloc函数

  2. 倘若有子类需要销毁顺序应在父类上面,避免出现不必要的错误

    - (void)dealloc
       
            [子类变量  release];  
            [super dealloc];  
       
    

ARC工程如何转变为MRC工程

YES—->NO

MRC实战中常见错误

准备工作

创建一个工程–>创建一个名为List的类名—>类中创建一个name变量@property NSString *name;—->重写dealloc方法(这样内存运用的得当否直接根据打印看到)

    -(void)dealloc
    
       NSLog(@"我的内存要被释放了");
       [super dealloc];
    

1. 使用变量没有遵守配对原则,造成的内存泄露

#import <Foundation/Foundation.h>
#import "List.h"
int main(int argc, const char * argv[]) 
@autoreleasepool 

    List *l=[[List alloc]init];   // reatinCount=1

    l.name=@"苹果";

    NSLog(@"%lu",l.retainCount);

    //[l release];
      
      return 0;
  

运行结束后l的引用计数仍然为1,并没有调用dealloc

2.遵守配对原则但由于错误使用nil,造成的内存泄露

     List *l=[[List alloc]init];
     l.name=@"苹果";
    NSLog(@"%lu",l.retainCount);
    l=nil;
    [l release];

在操作类对象的时候喜欢在最后一次release的后面讲对象=nil,避免其他地方引用对象造成崩溃,但放的位置不正确则会出现像上面那样的内存泄露 [l release]此时等价于[nil release],而l的引用计数为1,并没有及时释放

3.提前释放对象,造成野指针操作

 List *l=[[List alloc]init];
    l.name=@"苹果";
    NSLog(@"%lu",l.retainCount);
    List *l1=l;
    [l release];
    NSLog(@"%@",l1.name);  

l1=l,此时有两个指针同时指向同一个类地址,当一个指针release造成 reatinCount=0释放 了类的内存空间,而另一个指针也将指向空,就会引发野指针异常

4.当一个对象retainCount已经为0 时,调用retain方法,是不会使得对象起死回生的,同时还会发生野指针操作异常

    List *l=[[List alloc]init];
    l.name=@"苹果";
    NSLog(@"%lu",l.retainCount);
    [l release];
    [l retain];

5.MRC下set和get方法的重写

@interface List : NSObject

    NSString *_name;

-(void)setName:(NSString *)name;
-(NSString *)name;
@end 

@implementation List
-(void)setName:(NSString *)name

    if (_name!=name) 
    [_name release];
    _name=[name retain];
    

-(NSString *)name

    return _name;

@end

以上是关于iOS内存管理机制解析之MRC手动引用计数机制的主要内容,如果未能解决你的问题,请参考以下文章

Swift的自动引用计数

ARC内存管理机制详解

iOS内存管理-ARC

内存管理

iOS面试题之内存管理

iOS之深入解析内存管理MRC与ARC机制