内存管理:(只适用于堆内存开辟得到的变量) 堆空间由程序员手动(Coding)创建,也应由程序员手动释放,确保堆空间正确释放和正确维护对象的生命周期,称为内存管理。
OC是通过引用计数来对内存进行管理的,核心思想是遵循“谁创建,谁释放;谁引用,谁管理”的机制。
引用计数简单来说就是统计一块内存的所有权,当这块内存被创建出来的时候,它的引用计数从0增加到1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时候有另外一个对象或指针指向这块内存,那么为了表示这个后来的对象或指针对这块内存的所有权,引用计数加1变为2,之后若有一个对象或指针不再指向这块内存时,引用计数减1,表示这个对象或指针不再拥有这块内存的所有权,当一块内存的引用计数变为0,表示没有任何对象或指针持有这块内存,系统便会立刻释放掉这块内存。
ARC(自动内存管理)iOS5引入和MRC(手动内存管理)。ARC的本质其实就是MRC,只不过是系统帮助开发者管理已创建的对象或内存空间,自动在系统认为合适的时间和地点释放掉已经失去作用的内存空间,原理是一样的。虽然ARC操作起来很方便,不但减少了代码量,而且降低了内存出错的概率,但因为ARC不一定会及时释放,所以程序有时候可能会占用内存较大。而MRC若做得好,通过手动管理,及时释放掉不需要的内存空间,便可保证程序长时间运行在良好状态上。
在MRC中会引起引用计数变化的关键字有:alloc,retain,copy,release,autorelease。(strong关键字只用于ARC,作用等同于retain)
2.引用计数的内存回收方式,只是回收是做标记,并不抹除相关的数据。所以我们向一个已回收内存的对象发送一个tetainCount消息,它的输出结果是不确定的,如果该对象所占用的内存已经被复用了,那么就可以能造成程序的异常崩溃。
autorelease:它的作用于release类似,但autorelease会在程序走出自动释放池时释放
自动释放池底层怎么实现
自动释放池以栈的形式实现:当你创建一个新的自动释放池时,它将被添加到栈顶。当一个对象收到发送autorelease消息时,它被添加到当前线程的处于栈顶的自动释放池中,当自动释放池被回收时,它们从栈中被删除, 并且会给池子里面所有的对象都会做一次release操作
NSRunloop,runloop,autoReleasePool和thread的关系理解 - CSDN博客
先提出一个问题,在Iphone项目中,大家会看到一个默认的Autorelease pool,程序开始时创建,程序退出时销毁,按照对Autorelease的理解,岂不是所有autorelease pool里的对象在程序退出时才release, 这样跟内存泄露有什么区别?答案是,对于每一个Runloop, 系统会隐式创建一个Autorelease pool,这样所有的release pool会构成一个象CallStack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object会被release。
那什么是一个runloop?一个UI事件,一个timer,一个系统delegate都称之为runloop(不是NSRunloop),runloop实际上是从接收消息,然后处理完消息的一个完整过程。
自动释放池是由AutoreleasePoolPage以双向链表的方式实现的
当对象调用autorelease方法时,会将对象加入AutoreleasePoolPage的栈中
调用AutoreleasePoolPage::pop方法会向栈中的对象发送release消息
作者:Draveness
链接:https://www.jianshu.com/p/32265cbb2a26
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
.autorelease pool和thread
多说一句,只有以上提到了3种runloop才会自动创建autorelease pool,thread是不会自动创建的,所以我们可以看到子线程中会有手动写的autorelease pool代码。这点以前搞混过,切记!
除了以上所述的关键字,还有一些方法会引起引用计数的变化,如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