iOS内存管理机制的原理是引用计数,引用计数简单来讲就是统计一块内存的全部权,当这块内存被建立出来的时候,它的引用计数从0增长到1,表示有一个对象或指针持有这块内存,拥有这块内存的全部权,若是这时候有另一个对象或指针指向这块内存,那么为了表示这个后来的对象或指针对这块内存的全部权,引用计数加1变为2,以后如有一个对象或指针再也不指向这块内存时,引用计数减1,表示这个对象或指针再也不拥有这块内存的全部权,当一块内存的引用计数变为0,表示没有任何对象或指针持有这块内存,系统便会马上释放掉这块内存。数组
其中在开发时引用计数又分为ARC(自动内存管理)和MRC(手动内存管理)。ARC的本质其实就是MRC,只不过是系统帮助开发者管理已建立的对象或内存空间,自动在系统认为合适的时间和地点释放掉已经失去做用的内存空间,原理是同样的。虽然ARC操做起来很方便,不但减小了代码量,并且下降了内存出错的几率,但由于ARC不必定会及时释放,因此程序有时候可能会占用内存较大。而MRC若作得好,经过手动管理,及时释放掉不须要的内存空间,即可保证程序长时间运行在良好状态上。spa
在MRC中会引发引用计数变化的关键字有:alloc,retain,copy,release,autorelease。(strong关键字只用于ARC,做用等同于retain)指针
alloc:当一个类的对象建立,须要开辟内存空间的时候,会使用alloc,alloc是一个类方法,只能用类调用,它的做用是开辟一块新的内存空间,并使这块内存的引用计数从0增长到1,注意,是新的内存空间,每次用类alloc出来的都是一块新的内存空间,与上一次alloc出来的内存空间没有必然联系,并且上一次alloc出来的内存空间仍然存在,不会被释放。对象
retain:retain是一个实例方法,只能由对象调用,它的做用是使这个对象的内存空间的引用计数加1,并不会新开辟一块内存空间,一般于赋值是调用,如:内存
对象2=[对象1 retain];表示对象2一样拥有这块内存的全部权。若只是简单地赋值,如:对象2=对象1;那么当对象1的内存空间被释放的时候,对象2便会成为野指针,再对对象2进行操做便会形成内存错误。开发
copy:copy一样是一个实例方法,只能由对象调用,返回一个新的对象,它的做用是复制一个对象到一块新的内存空间上,旧内存空间的引用计数不会变化,新的内存空间的引用计数从0增长到1,也就是说,虽然内容同样,但实质上是两块内存,至关于克隆,一个变成两个。其中copy又分为浅拷贝、深拷贝和真正的深拷贝,浅拷贝只是拷贝地址与retain等同;深拷贝是拷贝内容,会新开辟新内存,与retain不同;真正的深拷贝是对于容器类来讲的,如数组类、字典类和集合类(包括可变和不可变),假设有一个数组类对象,普通的深拷贝会开辟一块新内存存放这个对象,但这个数组对象里面的各个元素的地址却没有改变也就是说数组元素只是进行了retain或者浅拷贝而已,并无建立新的内存空间,而真正的深拷贝,不但数组对象自己进行了深拷贝,连数组元素都进行了深拷贝,即为各个数组元素开辟了新的内存空间。it
release:release是一个实例方法,一样只能由对象调用,它的做用是使对象的内存空间的引用计数减1,若引用计数变为0则系统会马上释放掉这块内存。若是引用计数为0的基础上再调用release,便会形成过分释放,使内存崩溃;内存管理
autorelease:autorelease是一个实例方法,一样只能由对象调用,它的做用于release相似,但不是马上减1,至关于一个延迟的release,一般用于方法返回值的释放,如便利构造器。autorelease会在程序走出自动释放池时执行,一般系统会自动生成自动释放池(即便是MRC下),也能够本身设定自动释放池,如:io
@autoreleasepool{容器
obj= [[NSObject alloc]init];
[obj autorelease];
}
当程序走出“}”时obj的引用计数就会减1.
除了以上所述的关键字,还有一些方法会引发引用计数的变化,如UI中父视图添加、移除子视图,导航控制器或视图控制器推出新的视图控制器以及返回,容器类(数组、字典和集合)添加和移除元素。
当子视图添加到父视图上时,子视图的引用计数加1,移除时引用计数减1,若父视图引用计数变为0内存被释放,其全部的子视图都会被release一次,即引用计数减1,原则上只有这三种状况子视图的引用计数会发生变化,其余如父视图引用计数的加减都不会影响到子视图。
容器类的状况与视图相似,添加元素,该元素引用计数加1,移除元素,该元素引用计数减1,容器引用计数变为0所占用内存被释放,容器全部元素release,引用计数减1,其余状况下容器自己的引用计数变化不会影响到容器内元素的引用计数变化。
导航控制器或视图控制器推出新的视图控制器会使被推出的视图控制器的引用计数加1,该视图控制器返回的时候引用计数减1,具体方法以下:
导航控制器推出视图控制器调用方法:- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
返回时一样用导航控制器调用方法:- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
视图控制器推出视图控制器调用方法:- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion
返回时被推出的视图控制器调用方法:- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion
应注意:当一个对象的引用计数变为0占用内存被释放时,会调用- (void)dealloc方法,因此若是在MRC下自定义类,必须在该方法里将该类中属性关键字设置为retain或copy的属性release一次,以避免形成内存泄露,重写方法不要忘记在第一行添加[super dealloc];。