zoukankan      html  css  js  c++  java
  • Objective-C 内存管理

    内存管理

    为什么要进行内存管理?
    因为设备的内存空间是有限的,如果一直占用,而不回收空间,内存就会被一直占用,导致内存不足,  系统就会就会报警,严重的可能直接退出程序,因此,在软件开发过程中,需要进行内存管理,以保证高效快速的分配内存,并且在适当的时候释放和回收内存资源。
     
    内存管理的范围?
    任何继承了NSObject的对象,对基本数据
    类型无效,主要对堆区的内存进行管理。
     
    为什么要对堆区的内存空间进行管理,基本数据类型不需要管理呢?
    因为基本数据类型的数据会被放入栈中,他们依次紧密排列,遵循先进后出的原则,系统会自动进行管理。 而对象类型会被放到堆中,堆中的内存是不连续的,无法自动释放,所以需要我们管理。
     
    内存管理的原理?
    (1)对象的所有权及引用计数器
          对象的所有权:任何对象都有一个或多个拥有者,只要一个对象至少还有一个拥有者,他就不会被释放
    (2) 任何自己创建的对象都归自己所有,可以使用alloc和new开头或名字中包含copy的方法创建对象,使用return来获得一个对象的所有权。
    (3) OC中都有专门8个字节的存储空间来存储引用计数器,用整数表示对象被引用的次数。
    引用计数器是判断对象是否回收内存空间的依据。
    (4) 给对象发送消息
             return  计数器+1,方法返回对象本身
             release  计数器-1,但不代表释放,autorelease 也可使引用计数器-1.
             retaincount消息  用来获得当前引用计数器的值 
     
    引用计数器为0,系统像对象发送dealloc消息,(调用[super dealloc]方法,一定要写在后面)释放相关资源,对象被回收后将不能在被使用(僵尸对象),僵尸对象不可复活,否则会导致程序崩溃,导致野指针错误
     
    如何防止野指针错误,在对象被释放后赋值为nil.
     
    内存管理的分类?
    MRC 手动内存管理
    ARC 自动内存管理
    垃圾回收   iOS不支持
     
    内存管理的原则?
    如果还有人使用某个对象,这个对象就不会被回收。
    如果有人想使用这个对象 那么就应给让对象的引用计数器+1
    如果不想使用这个对象,就有那个该让对象的引用计数器-1
    谁创建谁relesase   谁retain 谁release.有始有终 有加有减。
     
    内存研究的内容?
    野指针 内存泄露
    野指针 定义的指针变量没有初始化。指向的空间已经被释放
    内存泄露 :如果栈区的的空间已经被释放了,而堆区的空间还没与被释放,堆区的空间就被泄露了。 

     

     

     单个对象内存管理

      1. 野指针错误:

          访问了一块坏的内存

      2. 僵尸对象:

          如果一个对象已经被释放,这个对象被称为僵尸对象

      3. 空指针:

          没有指向任何东西的指针,给空指针发送消息不会报错

      4. nil和NULL的区别

         nil  对象指针

         NULL 类对象指针

       5. 避免使用僵尸对象的方法:

          对象释放了以后,给对象赋值为nil

       6. 单个对象的内存泄露

          情况1: 创建完成,使用之后,没有release

    情况2: 没有遵守内存管理原则

            Dog *d = [[Dog alloc] init]

     [d retain];

          情况3: 不当的使用了nil

    Dog *d = [[Dog alloc] init]

       d = nil;

          情况4:  在方法中对传入的对象进行了retain

    Dog *d = [[Dog alloc] init]

    [d compareColorWithOther: d];

     

    基本数据类型set方法的写法    直接赋值

      

         -(void)setSpeed:(int)speed
    
    {
    
     _speed = speed;
    
    }
    

    对于对象作为另外一个类的实例变量

      

      -(void)setDog:(Dog *)dog{
    
    if(_dog!=dog){   //先判断是不是原来的对象
    
    [_dog release];  //不是原来的对象做一次release,
    
    _dog = [dog retain];
    
    }
    
    }
     

    @property 参数
    格式:@property (参数1,参数2) 数据类型 方法名 

    1.是否要生成set方法

    readwrite : 同时生成setter和getter的声明、实现

    readonly :只会生成getter的声明和实现

    2.多线程管理

    nonatomic :性能高(一般用这个)

    atomic :性能低(默认)

    3.set管理相关参数

    retain :release旧值,return新值(适用于oc对象类型)

    assign : 直接赋值(默认,适用于非OC对象)

    copy : release旧值,copy新值
     
    (1)  assign 直接赋值

      -(void)setCar:(Car *)car{

    _car =car;

    }

    (2)  retain  release旧值,再retain新值

    在一个类中有关联其他对象的时候,这个对象的      @property(nonatomic,assign)  数据类型  方法名

         -(void)setCar:(Car *)car{
    
    if(_car!=car){   //先判断是不是原来的对象
    
    [_car release];  //不是原来的对象做一次release,
    
    _car = [car retain];
    
    }
    
    }
    

     

    (3) 是否要生成set方法(若只读,则不生成)

    readonly :只读,只会生成getter的声明和实现

    readwrite:默认的,同时生成setter和getter的声明和实现

    (4)多线程管理

        @property(nonatomic,assign)  数据类型  方法名

       高性能,一般使用nonatomic

    (5)  set和get方法的名称

    修改set和get方法的名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改名称一般用 在布尔类型中的getter 

     

    //替换set方法名称  @property(nonatomic,assign ,setter= isVip:) 
    
    //替换get方法名称  @property(nonatomic,assign ,getter = isVip)
    
    //替换set,get方法名称  @property(nonatomic,assign ,setter=isVip,getter = isVip:) 
    
     
    

     

     

     

    循环retain问题

    会导致两个对象都会内存泄露

    防止方法:

    1) 让某一个对象多释放一次(注意顺序) 

    2) 推荐方法: 一端使用assign 一端使用retain

    Dog.h
    #import <Foundation/Foundation.h>
    //#import "Person.h"
    @class Person;
    @interface Dog : NSObject
    //狗有个主人
    @property (nonatomic,retain) Person *owner;//这里用retain
    @end
    
    Dog.m
    #import "Dog.h"
    #import "Person.h"
    
    @implementation Dog
    - (void)dealloc
    {
        [_owner release];  //
        NSLog(@"Dog dealloc");
        [super dealloc];
    }
    @end
    
    Person.h
    
    #import <Foundation/Foundation.h>
    //#import "Dog.h"
    @class Dog;
    @interface Person : NSObject
    //人拥有一条狗
    @property (nonatomic,assign) Dog *dog;//这里用assign
    @end
    
    Person.m
    #import "Person.h"
    #import "Dog.h"
    
    @implementation Person
    - (void)dealloc
    {
        
    //    [_dog release];  //nil这里不在需要
        NSLog(@"Person dealloc");
        [super dealloc];
    }
    @end
    
    main.m    
    
    #import <Foundation/Foundation.h>
    #import "Dog.h"
    #import "Person.h"
    
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            Person *p = [Person new];  //1
            Dog *d = [Dog new];   //1
            
            //人有一条狗
            p.dog = d;    //  d   1
            d.owner = p;  //  p   2
            
            [p release];  //0
            [d release];  //
            
    //        [d release];
           
    //        [p release];
            
        }
        return 0;
    }
    
                                                                                                                                                                                                
    
     

    类方法不需要管理内存

    autorelease基本使用

    一个对象调用autorelease,将这个对象放到位于栈顶得的释放池

    @autoreleasepool

    {  //   

    }

    概念介绍:  一种支持引用计数器的内存管理方式,可以暂时保存某个对象,然后再内存池自己的排干的时候对其中的每个对象发送release消息

    好处:  不用担心对象释放时间,也不用担心什么时候调用release

    原理:

          autorelease实质上只是把对release的调用延迟了,对于每一个autorelease,该Object放入了当前的Autoreleasepool中,当该pool释放时,该pool中的所有Object都会被调用release;

     

    自动释放池: 特殊的栈结构(数据结构),和内存的栈区结构不同

    特点: 对象可以加入到自动释放池中,自动释放池结束的时候,会给释放池中的每个对象发送一条release消息

    使用:

    1)自动创建释放池

    autoreleasepool{

    }

    2)加入自动释放池,

    在自动释放池中

    [对象 autorelease]

    加入到自动释放池中以后,引用计数器不会变化

     

    基本用法总结

    1.会将对象放到一个自动释放池中

    2.当自动释放池被销毁时,会对尺子里的所有对象做一次release操作

    3.会返回对象本身

    4.调用完autorelease方法后,对象的计数器不变。

     

    int main(int argc, const char * argv[]) {
        //1 创建自动释放池
        Person *p = [Person new];  // p  1
        @autoreleasepool {//自动释放池开始
            
            [p run];
     
            NSLog(@"%lu",p.retainCount); // 1
            
            // [p autorelease] 把对象p加入到自动释放池中
            // 注意:加入到自动释放池中以后, 引用计数不会变化
            [p autorelease];  //加入自动释放池,
            NSLog(@"%lu",p.retainCount); // 1
            
            [p run];
            
        }//自动释放池结束   [p release];
        [p run];
        return 0;
    }
    

    注意及错误用法:

    1)并不是放到自动释放池中的代码产生的对象就会自动释放,如果需要释放,必须自动加入到自动释放池

    2)如果对象调用了autorelease但是调用autorelease的时候,没有在任何一个自动释放池中,此时该对象也不会被加入到自动释放池

    3)我们只需要在自动释放池代码块中调用autorelease就可以把对象加入到自动释放池

    4)内存较大尽量不要使用autorelease

     

    自动释放池嵌套使用

     

    为什么内存管理只管理内存对象?

    堆中内存不连续,无法自动释放!

     

    我们如何对内存对象进行管理!

    通过操作对象的引用计数器

     

    autorelease的应用场景 

    经常用来在类方法中快速创建一个对象

     

     
    ARC
    指针分类
    (1)强指针:默认情况下所有指针都是强指针  关键字__strong
    (2)弱指针:__weak关键字修饰的指针
     
    原则 :当开启ARC时,编译器将自动在代码合适的地方插入retain、release、autorelease.
              永远不要写retain、release、autorelease;
     
    判断准则:只要没有强指针,对象就会被释放
     
    ARC机制:

    1)判断是否是ARC机制

    查看项目信息,不能使用retain release和autorelease,retainCount ,不能调用[super dealloc]

    2)使用

    正常创建对象,不用手动释放对象

    ARC下单对象内存管理

      ARC机制下,对象没有被强指针指向,对象会立即释放空间

    (两个下划线)__strong 修饰的指针是强指针,可以不写 

                     __weak 修饰的指针是弱指针

     1) 强指针指向了其他内容,对于对象来说就没有强指针指向了

     2) 弱指针赋值为nil

     

    ARC下多对象的内存管理 

     

    ARC机制下不能使用retain 应该使用strong 和 weak

    ARC下循环引用问题

    循环引用时一端使用strong , 一端使用weak.

     

    ARC下set方法内存和@property参数

      原子性/读写 和MRC下一样

     MRC            ARC

    assign         assign 适用于非oc对象

    retain         strong(强指针) OC的其他对象  weak (成员变量是弱指针适用于oc对象)

    copy            copy

     

    ARC使用特点及注意事项

      特点: 

    1) 不允许调用retain release、retainCount

    2) 允许重写dealloc,但是不能调用[super dealloc] 

     

    注意事项:

      1)ARC中,只要弱指针对象不存在,直接把弱指针清空(赋值nil)操作

      2)__weak Person *p = [Person new]

    弱指针指向空间销毁过程: (1)释放对象空间  (2)指针赋值nil

     

     

     

     

    MRC转换为ARC

    edit->Refactor->convert to Objective-C ARC…简单代码

    ARC兼容非ARC的类

     转变为非ARC   -fno-objc-arc

     转变为ARC的    -f-objc-arc

     

  • 相关阅读:
    linux mysql添加用户名并实现远程访问
    bootstrap-datetimepicker时间控件的使用
    jquery图片左右来回循环飘动
    jquery 全选获取值
    设置linux编码utf-8
    nginx 自签名https
    Laravel 邮件配置
    memcachq队列安装
    开发与运维使用常用工具
    composer配置和安装php框架
  • 原文地址:https://www.cnblogs.com/yilizhijiaotianxiashao-yincaiersanshijianduo/p/4724696.html
Copyright © 2011-2022 走看看