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

    (一)手动管理内存

    栈:存放局部变量(所占用内存会自动销毁) -> 指向堆空间

    堆:存放对象(所占用内存需手动销毁)

    管理范围:所有继承NSObject的类对象

    1.内存泄露?内存泄露的后果?

    自己申请的内存,没有释放 会使内存中存在很多的垃圾,浪费不必要的内存

    2.应用计数器:用于计算对象被使用的次数,是一个整数(每个对象都有自己的引用计数器:占4个字节)

    (1)当使用alloc、new或copy创建新对象时,新对象的引用计数器被设置为1.

    (2)当引用计数器为0时,则此对象所占用内存就会被回收。(发送release消息时,计数器减1)

    (3)给对象发送retainCount消息获取当前的计数器值

    注:retain方法返回的是对象本身(有返回值)

    3.对象的销毁

    (1)引用计数器为0,对象占用的内存被系统收回。(对象变成僵尸对象。指向此方法的指针值变为0)
    (2)当对象被销毁时,系统会自动向对象发送dealloc消息。(对象遗言)
    (3)一般要重写dealloc方法。(必须调用super的dealloc)

    eg:

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

    4.概念

    (1)野指针:指向僵尸对象(不可用内存)的指针。
    注:给野指针发送消息会报错,报错提示:EXC_BAD_ACCESS
    (2)僵尸对象:所占用内存已经被回收的对象,僵尸对象不能再使用、
    (3)空指针:没有指向任何东西的指针(存储的东西是nil、NULL、0)
    注:给空指针发送消息不会报错

    5.内存管理原则:

    (1)当想使用(占用)某个对象时,就应该让对象的计数器+1 (让对象做一个ratain操作)
    eg:

    _age = [age ratain];
    

    (2)当不想使用(占用)某个对象时,就应该让对象的计数器-1 (让对象做一次release操作)
    eg:

    -(void)dealloc
    { 
            [_dog release];//对象计数器-1
            [super dealloc];
    }
    

    (3)谁retain,谁release;谁alloc,谁release。
    注:对象在set方法中赋值时,应该进行一次retain操作。(基本数据类型不需要管理内存 )

    6.set方法内存管理

    (1)只要调用了alloc,则必须要有release(或autorelease);
    如果对象不是通过alloc产生,则不需要release。

    (2)set方法代码规范
    1)基本数据类型:直接赋值(基本数据类型不需要进行内存管理)
    eg:

    - (void)setAge:(int)age
    {
    _age = age; 
    }
    
    

    2)OC对象类型
    eg:

    - (void)setCar:(Car *)car
    {
         if ( car != _car) // 1.先判断是不是新传进来的对象
         {
               [_car release]; // 2.对旧对象做一次release
               _car = [car retain]; //  3.对新对象做一次retain
         }                             
    }
    

    (3)dealloc代码规范
    1>一定要有[super dealloc],而且要放到最后。
    2>对self(当前)所拥有的其他对象做一次release
    eg:

    - (void)dealloc
    {
       [_car release]; // 一旦Person release,则车也应该release
       [super dealloc]; // 这段一定要放最后
    }
    

    7.@property 内存管理

    @property (参数) 对象
    eg :

    @property (nonatomic,retain) Car *car;
    

    (1)set方法内存管理的相关参数
    retain:生成的setter方法中会release旧值,retain新值。(适用于OC对象类型)
    assin:直接赋值(默认,适用于非OC对象类型)
    copy: release旧值,copy新值。
    (2)是否要生成set方法
    readwrite:可读写,同时生成setter和getter的声明、实现(默认)
    readonly:只读,只会生成getter的声明、实现。

    (3)多线程管理(多个线程同时调用某个方法)
    nonatomic:代表方法不要考虑线程安全性问题,告诉系统不在set方法中生成多线程代码。(高性能,禁止多线程,推荐使用)
    atomic:代表给方法进行加锁,保证线程安全(默认,低性能)
    线程保护机制:防止方法在未写入完成时,被其它线程调用,造成数据错误。

    (4)setter和getter方法的名称
    setter:setter = 方法名,决定了set方法的名称,方法名一定有冒号:
    getter:决定了get方法的名称。(一般用在BOOL类型)

    8.循环retain和class

    (1)@class使用方法:
    作用: @class Card 仅仅告诉编译器,Card只是一个类
    使用场合:用于.h声明此类,但是不会引入此类的方法和成员变量。
    注意点:仅仅声明这个类,不会将此类的方法和成员变量导入,如果需要,则应该在.m文件中#import此类。

    (2)引用一个类的规范
    1.在.h头文件中用@class来声明类
    2.在.m源文件中用#import来包含类的所有东西

    (3)@class优点
    1.解决循环包含的问题。只在.m 源文件中进行引用(可以循环声明,A中声明B,B中声明A)
    2.提高了性能。(如果被引入类的头文件进行了修改,不需要全部进行重新编译。)

    (4)@class 和 #import 区别
    1> #import方式会包含被引用类的所有信息,包括被引用类的变量和方法;(使用类所有信息,包括成员变量和方法)

    @class方式只是告诉编译器在A.h文件中 ,声明某个类,不知道此类的所有具体信息。(仅仅声明有这个类)

    2>如果有上百个头文件都#import了同一个文件,那么一旦被导入文件的头文件稍有改动,后面引用到这个

    文件的所有类的头文件都需要重新拷贝,效率较低。(A->B,B->C,C->D.....一旦A变动,则后面都需要重新编译。程序只编译.h文件)
    使用'@class'方式就不会出现这种问题了,只需在源文件中修改类即可,提高了效率。
    (解决了循环包含问题)
    3>在.m实现文件中,如果需要引用到被引用类的成员变量或方法时,还需要使用#import方式引入被引用类。

    2> 两端循环引用解决方法(循环retain)
    一端用retain,一端用assign。
    eg: Car 端 :

         @property (nonatomic,retain) Person *person;
    

    Person端:

        @propertor (nonatomic,assign) Car *car
    

    9. autorelease

    eg: Person *p = [[[Person alloc] init] autorelease]; //必须存在释放池,才能写autorelease
    作用:1>autorelease会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里所有对象做一次release。
    2>返回对象本身,且不影响对象计数器。
    注:池子被销毁时,对象不一定会被销毁,只是做一次release。释放池内可嵌套释放池
    eg:

    int main()
    {
       @autoreleasepool
       { // { 代表开始创建释放池
    
       } // } 代表销毁释放
    
    }
    

    优点:1>不用在关心对象释放的时间.
    2>不需要关心什么使用调用release。
    缺点:不能精确控制对象销毁时间。
    使用注意:1>占用内存较大的对象不要随便使用autorelease(不能精确控制对象销毁时间)
    2>占用内存较小的对象使用,则不会有太大影响。
    建议:尽量使用release,因为可以精确控制对象销毁。
    使用规范:1>系统自带的方法中,如果不包含alloc、new、copy,那么这些方法返回的对象都是已经autorelease的
    2>开发中经常写一些类方法快速创建一个autorelease的对象。(不使用类名,使用self)
    eg:

    + (id)Person  
    {  
       return [[[self alloc] init] autorelease];  
    }  
    

    (二)自动管理内存

    自动回收内存机制。
    优点:不需要人为添加内存管理代码,提高了编程效率与安全性。

    1.概念:编译器会自动在适当的地方插入适当的retain、release、autorelease语句。(属于编译器特性)

    2.ARC的判断标准:

    只要没有强指针指向对象,就会释放对象。
    eg: Person *p = [[Person alloc] init];
    p = nil;
    代码解析:默认情况下,p是强指针。当p等于空时,就没有强指针指向Person对象,这时候编译器会自动将Person对象销毁。

    (1)强指针:默认情况下,指针都是强指针(__strong)
    (2)弱指针: __weak 修饰
    eg: __weak Person *p2 = p ; (p2就是个弱指针)

    3. ARC特点:

    (1)不允许手工调用release、retain、autoretain。
    (2)允许重写dealloc,但是不允许调用[super dealloc];
    (3)@property参数
    strong:成员变量是强指针,相当于以前retain(使用OC对象)
    weak:成员变量是弱指针,相当于以前assign(使用OC对象)
    assign:基本数据类型,直接赋值。(使用非OC对象)
    (4)以前的retain,全部改为strong,其余不变
    eg: @property (nonatomic,retain) Car *car;
    改为:@property (nonatomic,strong) Car *car;

    4.某.m文件不需要ARC方法

    不需要ARC: 添加-fno-objc-arc

    需要ARC:-f-objc-arc

    5.解决循环引用问题

    1>ARC
    一端用strong,一端用weak
    eg:
    Dog 端 : @property (nonatomic,strong) Person *person;
    Person端:@propertor (nonatomic,weak) Dog *car

    2>非ARC
    一端用retain,一端用assign
    eg: Dog 端 : @property (nonatomic,retain) Person *person;
    Person端:@propertor (nonatomic,assign) Dog *car

  • 相关阅读:
    波段是金牢记六大诀窍
    zk kafka mariadb scala flink integration
    Oracle 体系结构详解
    图解 Database Buffer Cache 内部原理(二)
    SQL Server 字符集介绍及修改方法演示
    SQL Server 2012 备份与还原详解
    SQL Server 2012 查询数据库中所有表的名称和行数
    SQL Server 2012 查询数据库中表格主键信息
    SQL Server 2012 查询数据库中所有表的索引信息
    图解 Database Buffer Cache 内部原理(一)
  • 原文地址:https://www.cnblogs.com/wlios/p/4631895.html
Copyright © 2011-2022 走看看