黑马程序员------OC 内存管理MRC和autorelease pool

 ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

内存管理

1.内存管理概念

      由于移动设备的内存机器有限 所以每个被占用的内存也是有限的。不用的内存是余姚回收的,否则程序会崩溃

 

    oc 管理内存的范围: 管理任何继承NSObject的对象,对其他的基本数据类型无效

      基本数据类型数据占用的存储空间是固定的 一般存储在栈区。

      对象类型是程序运行过程中动态分配的,存储在堆区,内存管理主要是 对堆区的对象 的内存管理

    oc内存管理分类:MRC(手动管理内存) ARC(自动管理内存)

  2.引用计数器

       引用计数器是用来保存当前对象有几个东西在使用它(数字),在对象里有一块专门的空间大小为8个字节来存储

       引用计数器的作用 用来判断对象是否应该回收(如果对象不等于nil 当引用计数器为0,此时要回收对象的内存空间)

        引用计数器的操作

           retain 使得引用计数器 +1

           release 使得引用计数器 -1

           retainCount 得到引用计数器的值

    如果一个对象被释放的时候,就会调用“临终遗言”(dealloc方法)

    注意:

         1dealloc 方法是NSObject 的,一般我们要重写dealloc方法

         2)在dealloc 方法内部,要调用[super dealloc];

 

 #import 

@interface Person : NSObject

@end
#import "Person.h"

@implementation Person
//dealloc方法,是对象临终的遗言方法
//对象被销毁时,会默认的调用该方法
//dealloc方法 是系统根据引用计数器的值,自动调用的
- (void)dealloc{
  //先释放子类自己的空间
    NSLog(@"person dealloc");
   //再释放父类的
    [super dealloc];
}

@end
#import 
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //用person实例画一个对象
        Person *p =[[Person alloc] init ];
        //查看有几个拥有者
        NSUInteger count =[p retainCount];
        
        NSLog(@"count = %lu",count);//count =1
        
        [p release];//对象要被回收。 使用release 给引用计数器-1
                     //这时retainCount 为0 对象被回收掉用dealloc 方法
        
        
    }
    return 0;


 

注意:永远不要直接通过对象调用dealloc方法。对象一旦被回收不可再用,坚持使用会使程序崩溃

  3.内存管理的原则

      如果对象有人使用,就不应该回收

      如果你想使用这个对象,应该让这个对象retain  一次

      如果你不想使用这个对象你应该然然这个对象 release  一次

       谁创建谁 release 

       谁retain release 

 

#import 

@interface Dog : NSObject
-(void)eat;
@end
#import "Dog.h"

@implementation Dog
-(void)eat{
    NSLog(@"狗在吃东西");
}

@end
#import 
#import "Dog.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //创建 new  alloc init  copy
        Dog *bigYellowDog =[[Dog alloc] init];
        
        Dog*jb =[bigYellowDog retain];//  引用计数器+1 当前值为2
          [bigYellowDog release]; //谁retain 谁release
        //只有保证谁创建谁release,才能保证对象被回收
        [bigYellowDog release];
      
        
        Dog *byd = [[Dog alloc] init];
        [byd eat];
        //如果一个对象已经被释放了,这个对象就称之为僵尸对象
        [byd release];
        //这句话佛人情况下不会报错
        //如果要报错,要开启僵尸对象检测,
         //byd指针也就是野指针
        [bye eat]
        
        [byd retain];//byd已经是僵尸对象了 不能复生
    }
    return 0;
}

 

4.内存管的研究内容

   1)野指针  定义的指针变量没有初始化  指向的空间已经被释放

   2)内存泄露

     { Person *p=[Person new]; }

   p 在栈区   [Person new];在堆区 

   如果栈区的已经被释放了,而堆区的空间还没有被释放,堆区的空间就被泄露了

注意: p=nil 空指针 没有志向任何店东西的指针 ,给空指针发送消息不会报错。

5.单个对象的内存管理

#import 

@interface Dog : NSObject
- (BOOL)compareColorWithOther:(Dog*)dog;
@end
#import "Dog.h"

@implementation Dog
- (BOOL)compareColorWithOther:(Dog*)dog{
    
    [dog retain];//让传入的对象的引用计数器+1
    return YES ;
}@end
#import 
#import "Dog.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        Dog * d= [[Dog alloc] init]; //1
        
        [d release];//1--》0
        //给空指针发送任何消息,都没有效果
        //[nil run];
        //避免使用僵尸对象方法是,对象释放了以后,给对象赋值为nil
        //d =nil; //nil  给对象赋值 , Nil类对象
       // [d run];
        //单个内存泄露问题
          //内存泄露情况1  没有错遵守内存故那里原则,创建完之后没有release;
        //Dog *d = [[Dog alloc] init];
        //内存泄露情况2.没有遵守内存管理原则
        Dog *d = [[Dog alloc] init];//1
        [d retain];//2
        [d release];
        //retain 完了之后额米有release
        //内存泄露问题3 不当的使用nil
        //Dog *d =[[Dog alloc] init];//1
        //d=nil;
        //[d eat]
        //[d release]
           //内存泄露情况4 在方法中对传入的对象进行了retain;
        Dog* d =[[Dog alloc] init];//1
        //对象依然被泄露了
        [d compareWhithOther:d];//2
        [d release];
    }
    return 0;
}


 

6.多对象内存管理

   set 方法内存管理

   原则: 如果在一个类中,有其他类的对象(关联关系)

        set方法书写的时候要判断是否是同一个对象,release 旧值,retain新值。

            - (void)setDog:(Dog*)dog{

                //判断对象是否是原对象

                if(_dog =dog){

                    //release 旧值

                    [_dog release];

                  //retain 新值 ,并且赋值给实例变量

                _dog =[dog retain];

            }

        }

#import 

@interface Car : NSObject
@property int speed;
-(void)run;
@end
#import "Car.h"

@implementation Car
- (void)dealloc{
    NSLog(@"车被销毁了%d",_speed);
    
    [super dealloc];
    
}
-(void)run{
    NSLog(@"车以%d 的速度奔向拉萨",_speed);
}

@end

#import 
@class Car;


@interface Person : NSObject
{
    Car *_car;
}
@property (assign)NSString * name;
//拥有一辆车

-(void)goLasa;
- (void)setCar:(Car *)car;
-(instancetype)initWithName:(NSString*)name;
@end
#import "Person.h"
#import "Car.h"

@implementation Person
-(instancetype)initWithName:(NSString*)name{
    if (self =[super init]) {
        _name = name;
    }
    
    return self;

}
-(void)dealloc{
    
    [_car release ];
    NSLog(@"人已经挂了");
    //让父类释放
    [super dealloc];

}
-(void)goLasa{
    [_car run];
}
- (void)setCar:(Car *)car{
    //如果是_car == car 这是同一对象 ,那就不需要relaese
    if (_car != car) {
        [_car release];
        _car =[car retain];
    }
}
@end

#import 
#import "Person.h"
#import "Car.h"



int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p =[[Person alloc] initWithName:@"凤姐"];
        
        Car * bmw =[[Car alloc] init];
        bmw.speed =200;
        //给凤姐一辆车
        [p setCar:bmw];
        //去拉萨
        [p goLasa];
         [bmw release];
        
          [p goLasa];
         //创建新车
        Car *byd =[Car new];
         byd.speed =100;
        //凤姐给新车
        [p setCar:byd];
        [p goLasa];
          [byd release];
        
          [p release];
       
       
        
        
        
}
    return 0;
}
      }

  7.@property参数

      原子性 atomic 对属性加锁,多线程下线程安全,默认值

            nonatomic 对属性不加锁 多线程下不安全,但是速度快

      读写性 readwrite 生成gettersetter 默认值

            readonly  只生成getter方法

      set方法处理(内存管理)

                assign  直接赋值 默认值

                retain   release原来的值,再retain新值

                  copy   release原来的值,再copy新值

    什么时候使用retain 

    在一个类中有关联其他对象的时候,这个时候的@property (nonatomic,retain)

     什么时候使用assign  实例变量是最基本的数据的时候

    //这个时候会生成 setget方法的声明和实现

      readobnly 只会生成 get方法。默认的时readwrite

    @property (nonatomic,assign)int Num;

    

    替换set方法的名称 @property(nonatomic ,setter=isVip:)

         [p setVip: ispYES];//--->[p isVip:YES]

    替换个get方法的名称 @propery(nonatomic,setter=isVip:,getter=isVip);

    @class 的使用

  可以简单的引用一个类 

    @class Dog //类的引入

     仅仅是告诉编译器:Dog是一个类;并不会包含Dog这个类的所有内容

    

    具体使用  在.h文件中使用@class引用一个类;在.m文件中使用#import包含这个类的.h文件

    #import作用:要把映入的头文件内容拷贝到写#import处 ,如果Person.h文件内容发生变化,此时的所有的Person.h这个头文件的类都要重新编译

   使用格式  @class  类名

        @clss xxx  

      含义:是告诉编译器 xxx是一个类 至于有那些属性和方法此处不去检测

      好处是:如果xxx文件内容发生了改变,而不需要重新编译

    @class 可以解决循环引用的问题

        

      #import @class的区别

     作用上区别:#import会包含引用类的所有信息(内容),包括引用类的变量和方法

               @class仅仅是告诉编译器有这么一个类,具体这个类例有什么信息,完全不知道

     效率上的区别 

       如果有上百的文件都#import了同一个文件,或者这些文件一次被#import,那么一旦最开始的问价稍有改动,后面引用到这个文件的所有类都需要重新编译一边,编译效率非常低

 8.autorelease基本使用

       自动释放池 

    1)在ios程序运行过程中,会创建无数个池子,这些池子都是以栈结构(先进后出)存在的。

    2)当一个对象调用autorelease时,会将这个对象放到位于栈顶的释放池中

   基本方法

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

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

     3)会返回对象本身

     4)在调用完autorelease方法后,对象的计数器不收影响(销毁时影响)

  

     自动释放池的使用

     1)创建自动释放池

        @autoreleasepool{

       }

     2)加入释放池

           在自动释放池中

          [对象 autorelease];

      Person *p = [Person new ];

     //创建自动释放池

     @autoreleasepool {//自动释放池开始

     [p autorelease]//把对象放到自动释放池 ,引用计数器不会变化

 

       }//自动释放池结束 p对象被回收

 

    好处 (1)不再需要关心对象释放的时间  (2)不需要关心社么时候调用release

     

    autorelease是什么原理

      autorelease实际上只是把release的调用延迟了,对每个Autorelease ,系统只是把该Object放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用release

    autorelease 的使用注意

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

        Person *p =[[Person new] autorelease]; 

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

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

    自动释放池的栈结构(数据结构),和内存的栈区是不一样的 对象在 位于栈顶的释放池

 

 自动释放池的应用

      NSString * str = [NSString stringWithFormat:@"xxxx"];

        NSArray * array =[NSArray array]

    Person 类方法:

     帮我们自动创建对象,并且管理对象的内存(加入到自动释放池)

    Person *p =[Person person];

    1)创建一个对象 p

    2)用完之后,系统把对象释放掉p

    Person *p =[[Person alloc] init];

       p autorelease;

     +(id)person{

         //创建对象

        return [[[Person alloc] init] autorelease]; //返回对象空间

          //能够帮我们把对象给加入到自动释放池

     }

快速创建一个学生类初始化年龄
#import 

@interface Student : NSObject

@property (nonatomic,assign) int age;

- (instancetype)initWithAge:(int) age;

+ (instancetype)studentWithAge:(int)age;
@end
#import "Student.h"

@implementation Student
//重写构造方法给年龄初始化
- (instancetype)initWithAge:(int) age{
  //初始化父类 判断有没有成功
    if (self = [super init]) {
     //初始化子类。赋值年龄。
        _age =age;
    }
    return self;
}

+ (instancetype)studentWithAge:(int)age{


    return    [[[Student alloc] initWithAge:age]  autorelease];
}

-(void)dealloc{

    NSLog(@"Student dealloc");
    [super dealloc];
}

@end

#import 
#import "Student.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Student *stu =[[Student alloc] initWithAge:18];
        NSLog(@"stu.age = %d",stu.age);
        [stu release];
        
        //快速创建一个对象 给年龄初始化
         //1)定义类方法
        //2)类方法有参数,传递一个年龄
        Student *stu1 =[Student  studentWithAge:18];
        NSLog(@"stu1.age = %d",stu1.age);
    }
    return 0;
}



你可能感兴趣的:(黑马程序员------OC 内存管理MRC和autorelease pool)