内存管理机制


Objective-C中提供了两种内存管理机制MRC(MannulReference Counting)和ARC(Automatic Reference Counting),分别提供对内存的手动和自动管理,来满足不同的需求.

 

ARC:

 

ARC是Auto Reference Counting的缩写,即自动引用计数,由编译器在代码合适的位置中自动添加retain/Release/Autorelease/dealloc方法从而进行内存管理.

 

ARC几个要点:

 

  • 在对象被创建时 retain count +1,在对象被release时 retain count -1.当retain count 为0 时,销毁对象。
  • 程序中加入autoreleasepool的对象会由系统自动加上autorelease方法,如果该对象引用计数为0,则销毁。

 

那么ARC是为了解决什么问题诞生的呢?这个得追溯到MRC手动内存管理时代说起。

 

MRC下内存管理的缺点:

 

  • 当我们要释放一个堆内存时,首先要确定指向这个堆空间的指针都被release了。(避免提前释放)
  • 释放指针指向的堆空间,首先要确定哪些指针指向同一个堆,这些指针只能释放一次。(MRC下即谁创建,谁释放,避免重复释放)
  • 模块化操作时,对象可能被多个模块创建和使用,不能确定最后由谁去释放。
  • 多线程操作时,不确定哪个线程最后使用完毕

 

 

 

 

在ARC中与内存管理有关的标识符,可以分为变量标识符(_strong,  _weak, _unsafe_unretained, autoreleasing)和属性标识符(nonatomic/atomic, assign/retain/strong/weak/unsafe_unretained/copy,readonly/readwrite),对于变量默认为__strong,而对于属性默认为unsafe_unretained。也存在autoreleasepool。

 

 其中assign/retain/copy与MRC下property的标识符意义相同,strong类似与retain,assign类似于unsafe_unretained,strong/weak/unsafe_unretained与ARC下变量标识符意义相同,只是一个用于属性的标识,一个用于变量的标识(带两个下划短线__)。所列出的其他的标识符与MRC下意义相同。

 

(1)对于assign,你可以对标量类型(如int)使用这个属性。你可以想象一个float,它不是一个对象,所以它不能retain、copy。

 

(2)对于copy,指定应该使用对象的副本(深度复制),前一个值发送一条release消息。基本上像retain,但是没有增加引用计数,是分配一块新的内存来放置它。特别适用于NSString,如果你不想改变现有的,就用这个,因为NSMutableString,也是NSString。

 

 

 

MRC:

在MRC的内存管理模式下,与对变量的管理相关的方法有:retain,release和autorelease。retain和release方法操作的是引用记数,当引用记数为零时,便自动释放内存。并且可以用NSAutoreleasePool对象,对加入自动释放池(autorelease调用)的变量进行管理,当drain时回收内存。

 

Strong 和 Weak 的区别:

强引用持有对象,弱引用不持有对象。 

强引用可以释放对象,但弱引用不可以,因为弱引用不持有对象,当弱引用指向一个强引用所持有的对象时,当强引用将对象释放掉后,弱引用会自动的被赋值为nil,即弱引用会自动的指向nil。

Strong 强引用,举个例子:

1 id __strong test0 = [[NSObject alloc] init]; /* 设为对象A*
2
3 id __strong test1 = [[NSObject alloc] init];/*设为对象B*/

test0 和 test1 都是强引用,test0是对象A的持有者,就是拥有A,test1是对象B的持有者,就是拥有对象B,若:

test1 = test0;/*对象A的持有者就变成了test1*/

这样对象B就没有了持有者,没有持有者的对象会被ARC回收,就是释放,这样:

test1持有对象A,test0也持有对象A。

 

weak 弱引用,主要作用是用来防治循环引用出现内存泄漏的问题,它主要是弱引用,弱引用就是不持有对象,只是指向这个对象,举个例子:

1 id __strong test0 = [[NSObject alloc] init]; /* 设为对象A*
2
3 id __strong test1 = [[NSObject alloc] init];/*设为对象B*
4
5 id __weak test2 = test0;/*test1持有对象A的弱引用*/

test0持有对象A的强引用,而test2持有对象A的弱引用,也就是说,test0还是持有A的,而test2弱引用了test0的对象A,并没有持有对象A,当test2离开了作用域,对对象A的引用就会失去,当对象A被释放掉之后,test2会被置为nil,并不会出现crash。若:

test1 = test0;/*test1强引用对象A*/

此时对象B因为没有持有者就会被释放。

 

再如:

 1 #import <Foundation/Foundation.h>
2
3 int main(int argc, const char * argv[]) {
4 @autoreleasepool {
5 id __weak obj0 = nil;
6 if (YES) {
7 id obj1 = [[NSObject alloc] init];  //默认为强引用,即为strong类型
8 obj0 = obj1;
9 NSLog(@"obj0: %@", obj0);
10 }
11 NSLog(@"obj0: %@", obj0);
12 }
13 return 0;
14 }
15
16 /*
17 * 输出结果
18 * obj0: <NSObject: 0x1003066c0>
19 * obj0: (null)
20 *
21 * 因为obj1生成的默认的为强引用(__strong),在超出if的作用域之后,obj1所持有的对象被释放,
22 * obj0为弱引用,所以obj0不持有对象,在obj1对象释放后,obj0自动的被赋值为nil
23 * 弱引用的特性是,不持有对象,即便是写成id __weak obj1 = [[NSObject alloc] init];
24 * 此代码系统会给与警告,因为这里obj1被声明成弱引用,那么在赋值之后,alloc出来的对象会被立即释放。
25 */

 

 

 

 

 

智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告