OC 内存管理

//
//  main.m

#import <Foundation/Foundation.h>
#import "person.h"
/*
 堆内存的三种常见问题:
 1.野指针问题:访问没有所有权的内存,如果想安全的访问,必须确保空间还在.
 
 2.过度释放:对同一块空间释放多次,立即crash.
 
 3.内存泄露:空间使用完之后没有及时的归还系统.
 
 */
/*
 内存管理的三种方式:
 1.垃圾回收机制(gc):由系统来管理内存,系统识别空间何时不使用,自动回收空间,不适合用于ios开发,java采用该机制
 
 2.MRC机制:是手动引用计数机制,由开发人员开辟空间,并且显示添加引用计数修改的代码,能够灵活的控制空间何时释放.
 
 3.ARC机制:自动引用计数机制是ios5.0推出的也是苹果推荐的内存管理方式,本质上还是基于MRC,只不过对于引用计数修改的代码由系统自动添加.
 
 MRC和ARC都是基于引用计数机制的
 
 
 */

/*
 
 内存管理黄金法则:
 如果你对一个对象做了 alloc copy retain 操作之后你就拥有了对象的所有权,你就有责任对他进行release或者autorelease.
 简单理解就是:就看自己有没有使用alloc copy,retain这三个方法,如果使用了就对应上release或者autorelease,没有使用,就和自己无关,不用管理.
 
 *//*
 能够让对象的引用计数发生改变的方法
    
    1.alloc在堆区开辟空间,空间从无到有,引用计数从0到1;
    2.retain 将原有对象的引用计数加1.
    3.release 将原有对象的引用计数直接减1.
    4autorelease延迟减1
    5.copy.会在堆区开辟新的空间,对新的空间的计数加1,原有对象的引用计数不变.

 */

int main(int argc, const char * argv[]) {
//   //alloc功能两个:开辟空间;让对象的引用计数由0变1.
//   person *per=[[person alloc]init];
//    NSLog(@"per=%p",per);
//    NSLog(@"per.name=%p",per.name);
//    //retainCount:它是系统提供的方法,用来计算一个对象的引用计数
//    //retainCount:它是MRC情况下才会有的机制,所以我们使用的时候应该将ARC改为MRC
//    NSLog(@"per=%lu",[per retainCount]);
//    //retain是对象的引用计数+1;
//    
//    [per retain];//2
//    NSLog(@"per=%lu",[per retainCount]);
//    [per retain];//3
//    [per retain];//4
//    NSLog(@"per=%lu",[per retainCount]);
//    
//    //release:使用对象的引用计数-1
//    [per release];
//    [per release];
//    [per release];
//   
//    NSLog(@"per=%lu",[per retainCount]);
 
    //copy
    //对对象发送一个copy消息,对象就会找到一个方法(copywithzone)方法执行
    //copy原理:生成一个新对象,并且使新对象的引用计数为1,他不改变原始对象的引用计数
    
//    person *per2=[per copy];
//   // NSLog(@"per2=%lu",[per2 retainCount]);
//    
//    NSLog(@"per2=%p",per2);
//    NSLog(@"per2.name=%p",per2.name);
//    
    //[per2 release];//自动调用dealloc方法
    
//@autoreleasepool : 自动释放池
    
    //在ios5.0后推荐使用
   // @autoreleasepool { }
    
    //[[NSAutoreleasePool alloc]init];
    
    
      
    //创建三个对象放入池子中
    //我们在使用的时候一个对象只能使用一次autorelease ,不要多次调用
    //   @autorelease他和我们release不同,autorelease是在未来某一时刻释放,而这个未来某一时刻指的是碰到自动释放池之后才会释放,而release会立即释放
//    person *p1=[[[person alloc]init]autorelease];
//    NSLog(@"p1=%lu",[p1 retainCount]);
//    
//    //系统推荐:
//    @autoreleasepool {
//        person *p3=[[[person alloc]init]autorelease];
//        @autoreleasepool {
//            person *p4=[[[person alloc]init]autorelease];
//            NSLog(@"p4=%lu",[p4 retainCount]);
//        }
//        NSLog(@"p3=%lu",[p3 retainCount]);
//    }// }相当于自动释放池释放的标记
  //自动释放池的对象被释放的时候,他里面等待的被释放的对象就会被释放
    //自动释放池是一栈的形式存在的,在池子释放的时候,会对池子里的所有对象发送一条release消息,最后进入池子的会被最先释放
    
    /*
     
     copy和retain的区别
     copy是创建一个县的对象,retain是创建一个指针,引用计数+1,copy表示两个对象的内容相同,新的对象retain为1,与旧有的对象引用计数无关,旧的对象没有发生变化,copy减少对上下文的依赖.
     retain属性表示两个对象地址相同(就是建立了一个指针,进行了指针拷贝),内容肯定相同,这个对象的retain值+1,也就是说retain是指针拷贝,copy是内容拷贝.
     
     
     */
    
    /*
     在ios中并不是所有的对象都支持copy,mutablecopy,遵守NSCopying协议的类可以发送copy消息,遵守NSMutablecopy协议的类才可以发送mutablecopy消息,假如发送了一个没有遵守上述两个协议而发送copy或者mutablecopy那么就会发生议程,但是默认的ios类并没有遵守这两个协议,如果想自定义一个copy那么就必须遵守NSCopying,并且copywithzone方法,如果项自定义一个mutablecopy那么就必须遵守NSMutablecopying,并且实现mutableCopywithzone方法
     
     */
    
   //copy:
    //浅拷贝:
    //不可变字符串,copy是浅拷贝.
//    NSString *str=[[NSString alloc]initWithFormat:@"光光"];
//    NSString *str1=[str copy];
//    
//    NSLog(@"str=%@,str1=%@",str,str1);
//    
//    NSLog(@"str= %lu,str1=%lu",[str retainCount],[str1 retainCount]);
//    //深拷贝
//    //深拷贝mutablecopy,拷贝出来的是一个可变的字符串对象
//    NSMutableString *str3=[str mutableCopy];
//    NSLog(@"str=%p,str3=%p",str,str3);
//    NSLog(@"str=%lu,str3=%lu",[str retainCount],[str3 retainCount]);
//    
//    
    /*
     
     浅拷贝:拷贝的是指针,也就是不会申请一块新的内存空间,元对象的内存空间引用计数+1
     
     深拷贝:拷贝的内容,也就是会申请一块新的内存空间,并把原内存空间的内容拷贝进去,所以原内存空间的引用计数依然还是1,新内存空间的引用计数由0变为1
     
     */
    
    //copy深拷贝
//    NSMutableString *Mstr=[[NSMutableString alloc]initWithFormat:@"小光"];
//  
//     NSString *mstr1 = [Mstr retain];
//    
//    NSLog(@"mstr1=%p,mstr=%p",Mstr,mstr1);
//    
//    
//    NSString *mstr2=[Mstr copy];
//    NSLog(@"mstr2=%p,Mstr=%p",mstr2,Mstr);
//    
//   // mutablecopy
//    
//    NSMutableString *mstr3=[Mstr mutableCopy];
//     NSLog(@"mstr2=%p,Mstr3=%p",mstr2,mstr3);
//    
    /*
     1.只有不可变字符串copy才是浅拷贝
     2.不管源字符串是否可变,质押是用 mutableCopy 出来的字符串就是可变的(深拷贝).
     */
    
    //数组内存管理:
    person *p1=[[person alloc]init];
    person *p2=[p1 copy];
    NSLog(@"p1=%p,p2=%p",p1,p2);
    NSLog(@"p1.name=%p,p2=name=%p",p1.name,p2.name);
    NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
    
    
    //把对象放入数组当中,对象的引用计数+1
    NSArray *array=[NSArray arrayWithObjects:p1,p2, nil];
    
    NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);

    //将对象再次放到数组当中,我们数组里边的元素(对象)引用计数继续+1.
    NSMutableArray *marray=[[NSMutableArray alloc]initWithArray:array];
    
    NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
    
    //将对象从数组中移除,对象的引用计数-1
    [marray removeObject:p1];
    NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
    //对数组进行一个release操作,数组内部元素的引用计数都会-1.
    [marray release];
   NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
    
    
    
   [marray release];
   
    return 0;
}
原文地址:https://www.cnblogs.com/huyibo/p/5475347.html