OC内存管理

内存问题

  1. 野指针异常:访问所有权的内存,如果想要安全访问,必须确保空间还在(确保访问的内存不是僵尸对象)
  2. 内存泄露:空间使用完之后没有及时释放
  3. 过度释放:对一块空间释放多次,立刻crash
  4. 内存溢出:所有存储空间被占用

管理内存的三种方式

  1. 垃圾回收机制:程序员只要开辟存储空间,系统会自动回收内存。Java采用的机制。
  2. MRC:手动引用计数机制,由开发员开辟空间,手动添加影响引用计数增加或减少的方法,能够灵活的控制空间合适释放
  3. ARC:自动引用计数机制,是iOS 5.0 推出的,基于MRC,不需要程序员手动添加管理内存代码,编译器会在合适的地方添加管理内存的代码

引用计数机制:

iOS采用计数器来管理内存,当你拥有这个对象的时候,需要使用该对象的引用计数+1,当对象的引用计数器为0的时候,表示没有任何对象对该对象持有,那么这个时候系统会

自动调用dealloc方法来回收对象的存储空间

影响引用计数器的方法

使引用计数器+1的方法: alloc, retain, copy

使引用计数器-1的方法:release, autoreleae

retainCount 是ARC才有的机制所以要将MRC转换ARC

如图所示:将ARC模式关闭

 

1.release 使用引用计数减一

1 Person *person = [[Person alloc]init];
2 NSLog(@"retainCount = %lu",person.retainCount);
3 [person release];
4 NSLog(@"retainCount = %lu",person.retainCount);

 

2. retain使引用计数加一

1 Person *person = [[Person alloc]init];
2 NSLog(@"retainCount = %lu",person.retainCount);
3 [person retain];
4 NSLog(@"retainCount = %lu",person.retainCount);

3.野指针和僵尸对象

1         Person *person = [[Person alloc]init];
2         NSLog(@"retainCount = %lu",person.retainCount);
3         [person release]; // 1
4         NSLog(@"%lu",person.retainCount);  // 1
5         
6         [person release]; //0      当对象的引用计数为0,系统自动调用dealloc方法
7         
8         person = nil; // 对象置为nil,防止野指针异常
// 僵尸对象指的是:对象的引用计数器变成0后,该块地址被回收,变成不可访问的内存。
// 野指针指的是:指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
// 空指针:没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错

 

4.开启 zombie 检测

 

5. 自动释放池

  

 // 定义一个自动释放池
        // 第一种形式
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // pool 1
        
        Person *p1 = [[Person alloc] init];
        NSLog(@"%lu", p1.retainCount);
        
        [p1 retain];  // 2
        [p1 autorelease];
        NSLog(@"p1 = %lu", p1.retainCount);
        NSLog(@"pool = %lu", pool.retainCount);
        [pool release];
       
        NSLog(@"p1 = %lu", p1.retainCount); // 1
  // 对象使用 autorelease是在未来的某一时刻让对象的引用计数器减一,这个某一时刻是指碰到自动释放池子之后才会释放

 
// iOS 5.0 之后推荐使用的
// 第二种形式
        
        @autoreleasepool {
            
             Person *p2 = [[Person alloc]init];
           // [p2 retain];
            p2.name = @"p2";
            [p2 autorelease];
            NSLog(@"p2 = %lu", p2.retainCount);
            
            
            Person *p3 = [[Person alloc]init];
            // [p2 retain];
            p3.name = @"p3";
            [p3 autorelease];
            NSLog(@"%lu", p3.retainCount);    
        }

// 总结:自动释放池的作用:自动释放池会在销毁的时候检查内部有没有autorelease对象,如果有autorelease对象,让该对象的引用计数做一次减一操作(即让池子内所有的引用对象减一)

// 销毁方式 以栈的形式销毁的

 

 

 

6. 内存管理原则

// 凡是使用alloc, retain让对象的引用计数加一,相应的就该使用release或者autorelease让对象的引用计数减一,业绩也是说增加的次数要和减少的次数相等,才能保障对象的引用计数始终唯0,对象才可以被销毁
// 不想等的情况下,会出现

// 1. 内存泄露:增加的次数大于减少的次数

// 情况一

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

// 情况二

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

[person2 retain]; // 2

[person2 release]; // 1

// 情况三

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

person3 = nil;

[person3 release];

// 2.过度释放:增加的次数小于减少的次数

Person *person1 = [[Person alloc]init]; // 1

[person1 retain]; // 2

[person1 release]; // 1

[person1 release]; // 0

[person1 release]; // 过度释放
Person *person =[[Person alloc]init];

[person retain];

[person release];

[person release];

person = nil;

NSLog(@"person = %lu",person.retainCount);

 

  

 

posted @ 2016-03-29 13:43  ywhb  阅读(166)  评论(0编辑  收藏  举报