注:本文为笔记形式,所以很多都是摘抄的.<<iOS 与OS X多线程和内存管理>>书中写的很棒,简单易懂,建议各位看官自己去看看.
前言
知其然而不知所以然,一向是开发人员所忌讳的.其实对于iOS的多线程和内存管理,当时学习iOS的时候就已经学习过了相关技术了,但是呢,随着工作的时间加长用的却是内存管理以及多线程越是越来不明白了,正应了开头的那句话,所以到春季这段时间,我都会以<<iOS 与OS X多线程和内存管理>>这本书为基础,内存管理,block和GCD的使用进行讲解说明,这一篇我们就说一下关于iOS中内存管理机制-引用计数.
内存管理的基础概念
我们都知道,内存管理分为五个区,分别是栈区,堆区,静态区,常量区,代码区,每个区都有着自己的特点(具体可查看),我们要知道我们内存管理的是内存中的堆区,在Xcode4.2之前,Object-C采用的是MRC(手动引用计数)机制,而在其之后,Object-C采用的是ARC(自动引用计数)机制.虽然我们现在很多时候用不到MRC机制,但是我们需要在MRC机制下运行代码了解程序猿在程序中是如何手动进行内存管理的.
对象的生成、持有、释放、废弃
在<<iOS 与OS X多线程和内存管理>>书中对于引用计数说到了以下的几个说法.接下面,我们就对这几个说法进行一一的说明.
- 自己生成的对象,自己持有.
- 非自己生成的对象,自己也能持有.
- 不再需要自己持有的对象时释放.
- 非自己持有的对象无法释放.
那么,对象的生成、持有、释放、废弃这几种方式在OC中都是如何表现的,看下表我们先大体粗略的了解一下.(这里我们不会相对autorelease
方法进行详细说明,请看本篇autorelease
模块)
对象操作 | OC对应方法 |
---|---|
生成并且持有对象,引用计数从0变为1 | alloc 、new 、copy 、mutableCopy 等 |
持有对象,引用计数+1 | retain 方法 |
释放对象,引用计数-1 | release 方法 |
废弃方法 | dealloc 方法 |
######自己生成的对象,自己持有 使用alloc
、new
、copy
、mutableCopy
这几种方式就说明自己生成的对象,并且自己持有.我们在实际开发过程中接触到alloc
、new
比较多,copy
、mutableCopy
是的比较少.
alloc
方法是我们经常用来创建对象的方法,使用alloc
方法retainCount(引用计数)为1,并且返回对象的指针.使用示例如下所示.
//obj的引用计数为1id obj = [[NSObject alloc]init];复制代码
new
方法和alloc
方法类似,也能生成并且持有对象.并且retainCount(引用计数)为1.示例如下所示.
//obj的引用计数为1id obj = [NSObject new];复制代码
copy
和mutableCopy
这两个方法都是生成并且持有对象的副本,两者的不同之处在于copy
生成的是不可变的对象,mutableCopy
生成的则是可变对象.具体的示例如下所示.
id obj = [NSObject new]; //copyObj的引用计数为1 id copyObj = [obj copy]; //mutableCopyObj的引用计数为1 id mutableCopyObj = [obj mutableCopy];复制代码
非自己生成的对象,自己也能持有
我们先看下面书中的例子,以alloc
、new
、copy
、mutableCopy
等方法之外的方法取得的对象,因为不是自己生成并且持有的,所以自己并不是对象的持有者,(请注意这是MRC环境下)
id obj = [NSMutableArray array];复制代码
上面的代码中,NSMutableArray对象被赋值给变量obj,但是变量obj却并没有持有该对象,我们需要使用retain
方法让obj持有对象.这时候,NSMutableArray的引用计数为2.如下所示.
[obj retain];复制代码
有人会问为什么引用计数是2,这是因为NSMutableArray对象被创建的时候,引用计数为1,然后经过retain方法操作之后,NSMutableArray对象的引用计数+1,所以为2.
不在需要自己持有的对象时释放
当我们持有的对象不再需要的时候,我们需要对持有对象进行释放.释放的方式使用release
这个方法实现,这个方法会使对象的引用计数减一,如果引用计数为0的话,系统会自己调用delloc
方法来释放对象.示例如下所示.
NSMutableArray * obj = [NSMutableArray array];[obj retain];[obj release];复制代码
无法释放非自己持有的对象
上面一块我们说到持有的对象,我们有义务释放,但是我们不能释放自己没有持有的对象,如果自己没有持有对象而且强行释放,那么应用程序会发生崩溃.比如,
NSMutableArray * obj = [NSMutableArray array];[obj retain];[obj release];[obj release];复制代码
autorelease
在MRC中,autorelease的使用大大的降低了我们代码的复杂度和错误率,它看起来很像ARC,但是实际上它类似于C语言的局部变量.这里我们不得不说NSAutoreleasePool这个类,这个类是我们经常提到的自动释放池.我们每一个程序中都存在一个Main函数,这是程序的主入口,其中@autoreleasepool {}
就是一个自动释放池.
NSAutoreleasePool对象类似于C语言的作用域,对象的创建和释放之间就是作用域.NSAutoreleasePool对象释放掉之后,它所对应的作用域里面的对象也会释放掉.
接下来,我们看一下autorelease和NSAutoreleasePool对象是如何配合使用的.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; id obj = [[NSObject alloc]init]; [obj autorelease]; [pool drain];复制代码
前面,我们说到retain
和release
对引用计数的影响?那么调用autorelease
的对象,它的引用计数是怎么变化的呢?
对象执行autorelease方法时会将对象添加到自动释放池中 当自动释放池销毁时自动释放池中所有对象作release操作 对象执行autorelease方法后自身引用计数器不会改变,而且会返回对象本身.autorelease实际上只是把对release的调用延迟了,对于每一次autorelease系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用Release。
结束
关于MRC以及引用计数相关的笔记就只有这么多了,建议各位看官自己去<<iOS 与OS X多线程和内存管理>>,最后还是<<iOS 与OS X多线程和内存管理>>的pdf版的下载传送门,各位看官可以自行去参考查看.