《理论篇》

《深层次探索系统的内存管理(mrc至arc)》

2019-06-28  本文已影响0人  不够果断是种癌

说明:本文为学习笔记,参考书籍《Objective-C高级编程ios与osx多线程与内存管理》,仅供自我学习。

大家看到内存的第一反应就会想到自动引用计数,其实引用计数式内存管理仅仅是思考方式而已。我们需要理解4个词“生成”“持有”“释放”“销毁”。

自己持有的对象,一旦不再需要,持有者有义务释放该对象,释放时调用release方法。对象如果被释放掉了就绝对不能被访问。这也是为block要在堆上面的原因。

自己生成而非自己所持有对象,若用retain方法变为自己持有,也同样可以用release方法释放掉。

使用autrorelease方法,可以取的对象,但自己不持有对象。autorelease提供这样的功能,使对象在超出指定的生存范围时能够自动并正确的释放(调用release方法)。

自己不能释放非自己持有的对象。一旦释放会导致奔溃。

下面我们直接看代码。

NSAllocateObject函数通过调用NSZoneMalloc函数来分配存放对象所需的内存空间,之后将该内存空间置0,最后返回作为对象而使用的指针。

对象的引用计数可以通过retainCount实例方法获得。引用计数为0时,调用dealloc方法来销毁对象。

引用计数表是一个散列表。

autrorelease当前超出作用域(相当于变量作用域时),对象实例的release实例方法被调用。

NSAutoreleasePool对象的生存周期相当于C语言变量的作用域。对于所有调用过NSAutorelease实例方法的对象,在NSAutorepleasePool对象时,都将调用release方法。用源码表示如下图:

在Cocoa框架中,相当于程序主循环的NSRunLoop或者在其他程序可运行的地方,对NSAutoreleasePool对象进行生成,持有和销毁处理。因此应用程序开发者并不一定得使用NSAutoreleasePool对象来进行开发工作。

NSRunLoop每次循环对过程都会不断执行一个操作。生成NSAutoreleasePool对象,应用主程序处理销毁NSAutoreleasePool对象。

尽管如此,但在大量长生autorelease的对象时,只要不销毁NSAutoreleasePool对象,那么生成的对象就不会被释放,因此有时会产生内存不足的现象。比如读入大量图像的同时改变其尺寸。图像文件读入到NSData对象,并从中生成UIImage对象,改成尺寸后生成新的autorelease的对象。由于没有销毁NSAutoreleasePool对象,最终会导致内存不足。

解决方法,有必要在适当的地方生成,持有或者销毁NSAutoreleasePool对象。

通常在使用OC中,也就是Foundation框架时,无论调用哪一个对象的autorelease实例方法,实现上是调用的都是NSObject类的aurorelease实例方法。但是对于NSAutoreleasePool类,autorelease实例方法已经被该类重载,因此运行时会报错。

在ARC中也是遵循下面的规则的:

因此新引入4个属性修饰符:

__strong 修饰符是id类型和对象类型默认的所有权修饰符。也就是说,id变量,实际上是被附加了所有权修饰符。

接下来我们看看__weak,其存在主要是为了解决相互持有造成内存泄漏的问题。

接下来我们看看__unsafe_unretained修饰符:

接下来我们看看__autoreleasing修饰符

使用__week修饰的对象必定被注册到authoreleasepool中的对象。

在iOS应用程序模版中,像下面的main函数一样,@authoreleasepool块包含了全部程序。

NSRunLoop等实现不论是否ARC,均能随时释放注册到autoreleasepoo;中的对象 。

无论是否ARC,只要对象的所有者不持有该对象,该对象就被销毁,也就是走dealloc方法。

另外,在不是ARC无效时必须要调用[super dealloc]。ARC的时候不必书写这个。

另外Core Founation对象框架生成的API生成并持有的对象可以用CoreFoundation框架的API进行释放。

上一篇下一篇

猜你喜欢

热点阅读