本文共 5938 字,大约阅读时间需要 19 分钟。
垃圾回收机制:(Garbage Collection),有系统管理内存,开发人员需要管理 注:OC从2.0之后就开始支持垃圾回收机制,但是只适用于OS开发,(苹果电脑的操作系统),我们iOS平台是不支持垃圾回收机制;(面试题) 不支持垃圾回收机制,OC是如何管理内存的呢? | | |
| | |
| | |
| | |
| | release/autorelese(不会立即释放且与@autoreleasepool配合使用) |
| | |
//图中需要照明的人数,就代表引用计数 //1.当第一人"需要照明",引用计数+1 有0-->1 //2.当第二个人"需要照明",引用计数+1 有1-->2 //3.当第二个人"需要照明",引用计数+1 有2-->3 //4.当有一个人"不需要照明",引用计数-1 有3-->2 //5.当再有一个人"不需要照明",引用计数-1 有2-->1 //6.当再有一个人"不需要照明",引用计数-1 有1-->0 2、iOS平台下适用计数器如何管理内存,有两种方式 1.MRC:(Manual Reference Counting),手动引入计数器,有开发人员通过手动引入计数器来管理内存。 2.ARC:(Automatic Reference Counting),自动引入计数器,由系统通过引入计数器管理内存 //学习好MRC是为了更好使用ARC,iOS5.0之后就有了ARC; 1.如果工程环境是ARC,而部分文件使用了MRC,使用一个参数 -fno-objc-arc 2.如果工程环境是MRC,而部分文件使用了ARC,使用一个参数 -fobjc-arc ============================================================== @interface Person : NSObject @property (nonatomic,copy)NSString *name; @implementation Person//dealloc 方法是对象被销毁的时候自动调用的方法,不需要手动调用,由于dealloc方法是重写的父类,所以重写此方法的时候,一定要把父类的方法内容也写上 { NSLog(@"Person%@对象被销毁了",_name); //以后重写dealloc方法时一定调用[super dealloc]; 且此方法一定要写在最下面 Person *p = [[Person alloc]init];//alloc会造成对象的引用计数器由0-->1 //如何判断一个对象是否被持有,就看它的引用计数 //retainCount :对象的引用计数 NSLog(@"%lu",p.retainCount); //计数器为1 //如果自己创建的对象不使用时,释放对象,使用release [p release];// NSLog(@"%lu",p.retainCount); 对象死了就不能再使用它了 // [p release]; 不要过度释放,也等于操作僵尸对象 Person *p2 = [[Person alloc]init]; //0--->1 3、retain可以让对象的引用计数 +1 //非自己创建的对象,自己也能持有 p2 = [p2 retain]; //由1--->2 NSLog(@"%lu",p2.retainCount); //非自己创建的对象,自己也能持有 Person *p3 = [p2 retain]; NSLog(@"%lu",p3.retainCount); //2--->3 [p2 release];//3-->2 [p2 release];//2-->1 [p3 release];//1-->0 Person *p4 = [[Person alloc]init]; p4.name = @"小骨"; [p4 retain];//2 [p4 retain];//3 [p4 retain];//4 [p4 release];//3 [p4 release];//2 [p4 release];//1 // [p4 retain];//人死不能复生,对象死也不能复生 1.retain : 计算器 +1 ,会返回对象本身;(返回值为id泛类型) 2.release : 计数器 - 1,没有返回值 3.retainCount 的作用:获取当前对象的计数器数值 4.dealloc 当一个对象被销毁的时候,系统会自动调用,再次方法中一定要调用[super delloc];且这句话要放到最后; //僵尸对象:所占内存被回收的对象,就叫僵尸对象,僵尸对象不能再使用 //空指针:没有志向任何东西的指针就叫空指针叫空指针,(nil,NULL,0),给空指针发送消息 // alloc 对应 dealloc 区别: [[Person alloc]init]; 内存永远不会被释放 // [[[Person alloc]init]release]; 创建的同时立即就被释放掉 //autorelease 相比 release,也能造成引用计数器-1,不过autorelease 不是立即-1,会在未来某段时间做-1操作; 6、 autorelease 执行实质,对一个对象使用autorelease 操作,这个对象的引用计数器不会立即减1,如果把这个autorelease 操作放到自动释放出中,会在出池子的一瞬间减1,如果你没有放到池子中,不会对autorelease 操作对象进行减1; 注意:你要使用autorelease 必须和自动释放池配合使用 // Person *p5 = [[Person alloc]init];//0--->1 // NSLog(@"%lu",p5.retainCount); ======================================================= // NSAutoreleasePool 自动释放池类 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; Person *p6 = [[Person alloc]init]; p6.name = @"白子画"; [p6 autorelease];//或者用[p6 release]; NSLog(@"%lu",p6.retainCount); [pool release]; //第二种形式 @autoreleasepool { Person *p7 = [[Person alloc]init]; p7.name = @"糖宝"; [p7 autorelease];//未来的时间减1,出自动释放池减1// [p7 release];//-1 //过度释放 NSLog(@"%lu",p7.retainCount); }//此时也会引起过度释放,是由autorelease引起的 8、 内存管理的原则 //水污染谁治理,谁alloc谁release,谁return谁release,autorelease //你想占用某个对象,就应该让对象的计数+1,(也就是让对象做以retain操作) //当你不想持有(占有)某个对象时,就应该让对象的引用计数-1,(也就是让对象做一release操作) 重复使用的释放可以设置带有参数的宏定义,减少繁琐的程序 #define kRelease_Safe(_point) [_point release];_point = nil; Person *p8 = [[Person alloc]init]; Person *p9 = [p8 retain]; // [p8 release];//对一个空指针发送消息,没有任何影响 9、 NSMutableArray *mArray = [[NSMutableArray alloc]initWithCapacity:0]; //向数组中添加十个人 for (int i = 0; i < 10 ; i ++) { Person *person = [[Person alloc]init]; person.name = [NSString stringWithFormat:@"%d",i]; //数组在添加元素的时候,会对添加的元素做一次retain操作 [mArray addObject:person]; kRelease_Safe(person); NSLog(@"%@",mArray); //数组在释放自己之前,会对之前添加到数组中的元素进行引用计数减1的操作 //此时我们没有alloc 也没有retain ,所以不需要对数组mArray2 的内存释放负责 NSMutableArray *mArray2 = [NSMutableArray array];// Person *p10 = [[Person alloc]init]; p10.name = @"朱然"; [mArray2 addObject:p10]; NSString *string = [[NSString alloc]initWithString:@"12345678912345"]; NSLog(@"%ld",string.retainCount); 总结:非重点,但是考试一般会问及: 当使用stringWithFormat:创建的字符串对象当长度小于10的时候,在常量区;大于等于10的时候,在堆区; //使用其他方法创建的字符串都在常量区 NSString *string2 = [NSString stringWithFormat:@"1234567890"]; NSLog(@"%lu",string2.retainCount); //没人去释放字符串,stringWithFormat: 计数器1,其他计数为-1; ====================================================== 10、 copy 对象能够使用copy操作的前提是,此类必须遵循NSCopying 协议 //浅拷贝,只拷贝地址,同时对象的引用计数+1;此时拷贝出来的对象原对象的所占的空间大小相等,内容也相等 //深拷贝 不止拷贝空间和内容,而且从新开辟了一块内存 区别:浅拷贝会造成原对象的引用计数加+1,而深拷贝不会造成原对象的计数加+1; @interface Person : NSObject<</span>NSCopying>必须遵循NSCopying 协议 @property (nonatomic,copy)NSString *name; NSLog(@"Person%@对象被销毁了",_name); - (id)copyWithZone:(NSZone *)zone{ //返回对象的时候要做一次retain操作,外界的接受者才持有这个对象 //深拷贝 返回的是新的对象,此时两个对象所占的空间大小相同,内容也相同 Person *p = [[Person allocWithZone:zone]init]; Person *p11 = [[Person alloc]init]; p11.name = @"笙萧默"; Person *p12 = [p11 copy]; NSLog(@"%@",p12.name); NSLog(@"p11 = %p p12 = %p ",p11,p12); ===================================================== 11、 new 申请创建对象的同时让其引用计数0-—>1(不常用) //new其实就做了alloc和init 两步操作,申请空间并初始化 // [Person new] = [Person alloc]init]; Person *p13 = [Person new]; p13.name = @"东方"; 1.引用计数+1(alloc ,copy , new , retain) 2.引用计数 -1 (release , autorelease) 3.要想内存不出现泄漏,引用计数-1的次数相等 4.一旦引用计数为0的时候系统会自动调用dealloc 方法 5.谁污染谁治理,谁alloc谁release,谁return谁release,autorelease