标签:
前两篇介绍了C与C++的内存管理,这一篇介绍一下Object-C的内存管理。
Object-C是C的超集,所有C语言的特性在Object-C都可以实现。
然而在内存管理上还是存在一些不同的地方。
Object-C即面向对象C语言,其大部分的类型基于Cocoa框架,常见的有NS开头类型。
所以Object-C中大部分类型也都是以类为基础的。
Object-C中类存放于堆而非栈,故一般类对象定义都以指针形式,如:
<span style="font-size:18px;">NSString * str = @"test";</span>
<span style="font-size:18px;">NSString test; //error</span>
按照C的管理规则,这些类型在局部代码块中也属于自动变量的范畴。
Object-C是C的超集,可能由于我看的资料比较少,在目前看过的Object-C资料看来,比较少提到类似C所提到的内存管理关键字,
内存区分类等。不过既然是C的超集,那么不管是关键字还是内存区分类,应该都是大同小异,这一点有哪位大神熟知的麻烦在下面评论区告知我一下。
下面引用前一篇的内存区分类图片来说明Object-C的内存分区:
由于在前一篇中介绍过各区的作用,这里不再赘述。
Object-C中的const存在常量区,extern,static还是存储于静态存储区,C中的五大存储类中的静态变量依然可以在Object-C中延续使用,如:
<span style="font-size:18px;">static CGFloat coordinatorX = 0.6; extern NSInteger sum = 2; //函数中 static Bool flag = 1;</span>
<span style="font-size:18px;">static const float = 2.0;</span>
non-Object 的自动变量还是存储于栈,如:
<span style="font-size:18px;">viewDidLoad { NSInteger num = 1; CGFloat x = 2; CGFloat y = 3; }</span>
而类变量存储于堆中。
Object-C在早期曾使用类似GarbegeCollection的垃圾回收机制来管理内存,不过后来逐渐被MRC取代,现在又被ARC取代。
上面提到Object-C中的对象都是放堆里,也是动态生成,这一点是Object-C与C在内存管理上最大的区别和Object-C 的特点。
而GarbegeCollection,MRC,ARC,便是用来对对象的管理,生成和释放,就如C语言中的malloc()-free()以另一种形式管理。
MRC与ARC
Object-C的内存管理中引入了引用计数retainCount的概念,顾名思义就是有多少个指针指向当前对象,当引用计数为0时,对象被释放。
MRC与ARC都基于Runtime动态实现,引用计数+1、-1,对象释放消息的发送都由Runtime来实现。
MRC(Manual Reference Counting)
MRC翻译成中文就是手动引用计数,在MRC中和C语言一样也有一些关键字,一般用于属性声明。
主要有几个,retain,assign,copy,release。
注意,下面举例代码都是在MRC环境下的!!!
Retain
当用retain 声明属性时,如:
<span style="font-size:18px;">@property (retain) NSString *name;</span>
那么当我们把一个字符串对象赋给name时,字符串的引用计数retainCount 会 +1。
也可以在生成对象时直接用,如:
<span style="font-size:18px;">NSString *temp = [[NSString stringWithString:@"hello world"] retain];</span>
在accessMethor中的实现是这样的:
<span style="font-size:18px;">- (void)name:(NSString *)name { if(self.name != name) { [self.name release]; self.name = [name retain]; } }</span>
Assign
assign与retain相反,用于属性声明时,只是简单的赋值,引用计数不变,如:
<span style="font-size:18px;">@property (assign) NSInteger *age;</span>且一般也只用于简单数据类型,如NSInteger,NSUInteger等。
在accessMethor中的实现是这样的:
<span style="font-size:18px;">- (void)age:(NSInteger *)age { self.age = age; }</span>需要注意的是,assign所指向对象被释放时assign的对象并不知道,这是如果使用的话会crash,称野指针。
copy
copy顾名思义就是赋值,在进行对象赋值时,复制新的对象进行赋值,原对象不变,如:
<span style="font-size:18px;">@Property (copy) NSString *str; NSString *temp = @"hello world"; self.str = temp;</span>
在accessMethor中的实现是这样的:
<span style="font-size:18px;">- (void)str:(NSString *)str { if(self.str != str) { [self.str release]; self.str = [str copy]; } }</span>
也可和retain一样在生成对象时使用:
<span style="font-size:18px;">NSString *temp = [[NSString stringWithString:@"hello world"] copy];</span>这样原来的对象将被自动释放,新对象赋值给temp。
release
release是引用计数减一,将一个对象从一个指针处释放使用release,如上述中的:
<span style="font-size:18px;">[self.str release];</span>当retainCount为0时对象自动销毁。
MRC是引用计数的手动管理方式,对于程序猿来说比较麻烦,稍不注意会出现野指针和内存泄露等问题。
MRC相比起C的内存管理方式的好处是使用引用计数简化了释放过程,更加安全。
比如在C语言中如果多处引用同一个对象,一旦在某一处释放了之后,其他都变成野指针,这样是比较危险的。
而MRC的好处在于,假如使用妥当,那么对象只有在各处释放之后,引用计数减少到0时才释放,这样子便不容易出现野指针。
然而MRC在操作上还是比较困难,需要程序猿在每时每刻清除知道哪些对象该释放哪些不该释放。苹果在iOS5之后推出了ARC自动应用计数,大大方便了程序猿的工作。
ARC(Auto Reference Counting)
ARC的引入进一步方便了OC中对象的内存管理。其引入了三个新的关键字,strong,weak,unsafe_unretained。
使用这三个新的关键字,我们不需要再去手动管理引用计数,只需在声明变量的时候附上关键字就可以了。
下面介绍这三个关键字:
strong
strong和MRC中的retain作用类似,称强引用。
应用于属性声明:
<span style="font-size:18px;">@property (strong) NSString *name;</span>在赋值时对象引用计数自动+1,当name指向其他对象时,原来的对象引用计数自动减一,不用手动release。
在临时变量也可以使用,如:
<span style="font-size:18px;">__strong NSString *str; NSString *str1 = @"hello world"; str = str1;</span>这时字符串对象引用计数+1。
值得注意的是临时变量默认为strong类型。
weak
weak和MRC中的assign作用相似,称弱引用。
应用于属性声明:
<span style="font-size:18px;">@property (weak) NSString *name;</span>在赋值时对象引用计数不变,当name指向其他对象时,原来的对象自动释放,不用手动release。
在临时变量也可以使用,如:
<span style="font-size:18px;">__weak NSString *str; NSString *str1 = @"hello world"; str = str1;</span>这时字符串对象引用计数不变。
当str1设为nil时,str不会变成野指针,这一点和assign不同,str自动设置为nil,因此比较安全。
weak多用于消除ARC中的循环引用,比如block中的循环引用,或用于delegate。
unsafe_unretained
unsafe_unretained与weak十分相似,都只是赋值,引用计数不变,不过unsafe_unretained顾名思义是不安全,如:
<span style="font-size:18px;">@property (unsafe_unretained) NSString *name;</span>
也可以在局部变量中加以声明,如:
<span style="font-size:18px;">__unsafe_unretained NSString *str; NSString *str1 = @"hello world"; str = str1;</span>当str1释放时,str就变成野指针了,这是不安全的。
值得注意的是类属性默认为unsafe_unretained类型。
相比MRC,ARC更加方便,但也存在循环引用导致内存泄露的问题,在使用时需多加留意。
小结:
Object-C是C的超集,内存管理上也存在栈,堆,静态存储区,常量区等,只不过Object-C有object变量和non-object变量之分。non-Object变量和C中的自动变量大致上相同,在局部代码块上属于自动变量,存放于栈中。而object变量便和C有一些不同,都是动态生成的,类似C中的malloc()-free(),存放于堆中。Object-C由此引入gabegeCollection,MRC,ARC等动态基于runtime的管理机制,以引用计数为基础,以retain,weak,copy,unsafe_unretained,strong,assign等关键字来管理引用计数。ARC相对MRC使用方便,不用程序猿手动释放,但也存在循环引用等缺点。
下一篇介绍Eventloop和autoreleasepool以及C,C++,Object-C的对比总结。
标签:
原文地址:http://blog.csdn.net/freedomking3/article/details/45130549