zoukankan      html  css  js  c++  java
  • 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];  
      }   
      

    ARCproject如何转变为MRCproject

    YES—->NO

    这里写图片描写叙述

    MRC实战中常见错误

    准备工作

    创建一个project–>创建一个名为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
    
  • 相关阅读:
    java中判断字符是否为英文字母、中文汉字或者数字
    JavaScript:多种定义数组的方式
    java位移运算符<<、>>、>>>
    安卓进阶:元注解Support Annotation Library使用详解
    正则:匹配引号内的字符串内容
    安卓:自定义字体
    安卓:Activity的自定义主题
    Pyhton学习——Day38
    测试用html
    Pyhton学习——Day37
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7251668.html
Copyright © 2011-2022 走看看