学习任何一门语言,都要深入地了解它对内存的控制。因为无论你编写的程序在什么系统的计算机上运行,都会涉及到内存管理的问题。
在我们之前编写的程序由于本身很小、运行时间很短,所以没有做内存管理相关的操作,这样做的后果就是操作系统会在程序运行结束后再回收所占用的内存。
在实际开发中是绝对不能这样做的,由于开发的程序本身可能很大,有些功能可能会一直运行(例如,QQ等可以在后台一直运行),所以在程序中及时的释放内存是非常必要的。
OC也不例外,无论你用OC做Mac OS X开发还是iOS开发,都要考虑你的程序如何在有限的内存条件下运行效率更高。
OC内存管理的方式
对于OC的内存管理,到目前为止,共有三种方式:
1、手动引用计数(MRC):对于两种开发都支持。采用这种方式,对编程人员本身的要求比较高,因为要时刻考虑是否释放内存。
2、自动引用计数:两种开发都支持。(Xcode4.2之后才可以使用,简称:ARC(Automatic Reference Counting),ARC是Mac OS X 10.7和iOS 5 引入的新的内存管理方式)
3、垃圾回收机制:只适用于Mac OS X开发。
为什么选择ARC
在Mac OS X 10.7和iOS 5之后的系统进行开发时,强烈建议使用ARC内存管理方式,在这种内存管理方式下编程,程序员不需要对内存的回收做太多的干预,ARC会帮我们完成。采用这种方式更容易使初学者接受。
了解手动引用计数
在学习ARC之前,必须了解手动引用计数是怎么实现内存管理的,因为自动引用计数是从手动引用计数的基础上实现的。ARC不需要程序员去过多地管理内存,所以如果想深入的了解内存管理,就要从MRC下手。
(由于现在Xcode的发展,新建的功能默认都是ARC的,所以在学习之前,要将ARC去掉,例子中会提到取消ARC的方法)
首先了解一个概念,引用计数:简单的理解,就是每个对象都拥有一个整数变量,苹果官方把这个变量就称作这个对象的引用计数。
手动内存管理的理论实现
OC是怎么通过这个变量来手动管理内存的呢?之前介绍过,在OC的程序中,使用最多的数据结构就是类,所以OC编程对于内存的管理关键在于类对象在什么时候释放。
当我们对一个类进行初始化时,用alloc为这个对象分配内存空间,在alloc的时候,对象的引用计数就初始化为1。
如果别的地方同样也使用到了这个对象,那么这个对象的引用计数+1。使用完成后,这个对象的引用计数-1。
提示:在程序中,让对象的引用计数做+1操作的方法是:[对象 retain],让一个对象的引用计数做-1操作的方法是[对象 release]。如果使用手动引用计数,首先在搞清楚retain和release的位置,如果搞错,程序会出错甚至崩溃。
当这个对象的引用计数变为0时,说明已经程序中已经不需要它了,那么此时,OC会自动销毁这个对象(OC会自动向这个对象发送一个dealloc消息,这一步不需要我们程序员操作)。
另外在创建一个OC工程时,我们总会看见在main程序入口函数中有这样一种结构:
@autoreleasepool {
}
通过翻译,得知它叫自动释放池,它是做什么的呢?在编程过程中,经常会遇到只使用了一次的对象,对于这种对象,我们如果每一个都进行release操作,就会非常麻烦。
这个时候,就要用到上面这种结构。它的使用简单的理解就是:把所有需要发送release消息的对象都记录下来(给这个对象发送autorelease消息,这样这个对象就会被记录),直到运行完自动释放池中的代码以后,OC会集中给被纪录的对象发送release操作。
如果采取上面这个结构,由于是集中释放内存空间,所以如果内存条件紧张的情况下,我们要在程序总多添加几个自动释放池,已达到及时释放内存的目的。
下面,我们通过一个例子,来感受一下手动引用计数和自动释放池的用法:
1、首先,创建一个工程,例如Demo;
2、将Demo的ARC模式去掉:(方法:在Xcode工程目录下找到Demo工程->在搜索框中输入:automatic后回车->会发现关于OC自动引用计数的设置->将Yes改为No就完成了)
3、下面创建一个Person类
4、在main.m文件中编写以下代码:
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
Person * person;
@autoreleasepool {
person =[[[Person alloc] init ] autorelease]; //通过autorelease将person对象添加到自动释放池中
NSLog(@"%ld",[person retainCount]); //发送retainCount消息,获得当前对象的引用计数的值。
[person retain]; //发送retain消息,添加一个person对象的引用,
NSLog(@"%ld",[person retainCount]);
}
NSLog(@"%ld",[person retainCount]); //自动释放池中的代码运行完成后,自动释放池会被销毁,其中所包含对象的引用计数都会-1,对于引用计数为0的对象会被销毁
return 0;
}
输出结果:
1
2
1
ARC模式
通过以上的学习,应该对非ARC模式下的手动引用计数的内存管理方式有了初步的认识,对于自动释放池来说,ARC或非ARC模式下都可以使用。下面来介绍一下在ARC模式下编程有什么特点。和非ARC有什么不同。
1、在ARC模式下编程,我们就不用考虑添加retain、release、autorelease、retainCount这些函数(方法),在我们程序编译的时候,ARC会帮我们添加。
2、在非ARC模式下,当某个类的对象的引用计数为0时,系统会自动向这个对象发送dealloc消息,在这个消息中,需要将这个类中声明的一些属性手动释放掉(通过[属性名 release]的方式)。但是在ARC中,不用这么做。
简单的总结本节讲的知识就是:在ARC下编写程序,对于程序员来说,不需要判断对象是否需要被释放,何时被释放。只需要考虑如何完成软件的各个功能。
在ARC模式下编程,基本上不需要程序员对内存进行管理,大大地提高了开发效率。
通过本节的学习,可以大致了解OC对内存的管理方式。在实际开发中,有时需要去手动的管理内存。但是更多时候不需要我们操心。但是也需要知道OC的内存管理到底是如何实现的,搞清楚内存管理,会使我们对OC的学习更透彻。