Objective-C学习——内存管理

一、概念

内存管理——是指在应用程序运行时进行内存分配和使用,结束时释放内存的过程。IOS设备的RAM(random access memory)大小有限,而应用程序运行时占用的内存都是取自RAM,所以程序运行过程中的内存管理尤为重要,超出一定的限制会收到内存警告,而对警告没有相应的处理就会导致进程被强制杀掉。随着应用程序不断的运行,会创建更多的实例,也会占用更多的内存,而大部分的对象并不是一直需要,所以应该在不需要该对象的时候释放它占用的内存,进而可以重用,内存的动态使用,释放,重用,需要有适当的管理,这也是内存管理的目的。也正是如此,不恰当的内存管理可能导致以下两种问题:

1、过早释放:在应用程序还没用完某个对象的时候就释放了该对象,这会导致程序的崩溃;

2、内存泄露:已经用完不会在使用的对象没有被释放,这将会导致相应的内存不能被重用。

二、类比

c、c++中也有相应的内存管理,c中用malloc和free来申请和释放一定的内存,c++中用new和delete,OC中alloc和dealloc来完成相应的任务。

malloc和free任务就是分配和释放一定字节大小的堆空间,例如:

char * buffer=malloc(100); //分配100个字节大小的内存
//do something with the buffer
free(p);		  //用完释放

new和delete的也有很多种用法,举个最简单的例子:

Foo *p = new Foo;
//do something with p
delete p;

现在看来,并不能简单的把alloc/dealloc类比为new/delete。new调用相应的构造函数完成了内存分配和初始化两个过程,delete则调用相应的析构函数完成释放的工作。由于管理的机制不一样,alloc是继承自NSObject的类方法,用于分配内存空间,每个类知道自己需要多大的内存,所以向类本身发送alloc消息就完成了分配内存的工作,初始化的工作是由另外一个实例方法完成的——init。所以OC中一般创建实例的步骤是:

1、alloc消息发送给类;

2、init消息发送给1中创建的新对象。

所以alloc就好像是new悄悄完成的内存分配,在OC中显示的表示出来为一个类方法;init就好比是C++中的构造函数,当然init也可以有各种的版本,但命名上一般都以init开头。在c++中有默认的构造函数,一般是一个没有参数的或者是参数有默认值的。但是在OC中都是显示的调用init方法,而且OC中不允许参数有默认值,所以默认的构造函数没有很实际的意义。OC中用指定的初始化方法来完成代码上的一种精简——将共同的代码放到一个指定的初始化方法中,通常它包含了最多的参数,而其他的init函数调用该指定的init函数,而给多出来的参数一些默认的值,也同样实现了默认参数的目的。

dealloc则是和alloc相对的,用于释放内存归还给堆。但是它两也不一样,首先alloc是类方法,而dealloc是实例方法。想想也知道必须这样,alloc用来创建实例对象,alloc消息发送时还没有实例产生,而dealloc是释放实例的内存空间,肯定是释放具体的某个实例,而不可能是释放类本身~

OC和C++另外一个区别是继承序列中构造顺序和析构顺序,c++中编译器自动帮你按照顺序从基类到子类调用构造函数,按照相反的顺序调用析构函数;但是OC中需要显式的发送init和dealloc消息给super。

好像说的有些远,通过类比也可以看出来对内存的管理,采用的不同的方式的差别。

三、管理方式

Objective-C提供了三种方式去管理内存:1、MRR(Manual Retain Release)手动管理,2、ARC(Automatic Reference Counting)自动引用计数,3、GC(Gaobage Conllection)垃圾回收

在IOS中不支持GC,只能采用前两种方式,ARC也是ios5带来的新特性,可以有效的减少代码量。不管是MRR还是ARC都是基于引用计数的基础上的,不同的是MRR需要手动的控制,而ARC实现了编译器自动控制。

内存管理模型是基于对对象的“所有权”(ownership)。任何一个对象都可以有一个或者多个拥有者(owener),当一个对象拥有至少一个拥有者时该对象存在,没有了所有者时,系统自动发送dealloc消息给该对象。

为了更加清晰的描述对对象的拥有和释放,遵循以下几点规则:

1、你拥有你创建的对象,也就是你拥有以以下一些字母开头的方法创建的对象——new,copy,mutableCopy,alloc,就比如newObject,copy,mutableCopy,alloc方法

2、你可以使用ratain方法增加对一个对象的所有。在一个方法体中你可以retain一个对象,这个对象会在该方法体内一直有效,而且你还可以把该对象作为返回值返回给该方法的调用者。在下面两种情况下需要用retain——a,访问方法(settter&getter)和init;b、在执行某些操作,你担心对象会释放掉。

3、当你不需要一个对象时,你应该放弃对它的所有权,即发送release或者autorelease。术语来讲,放弃一个对象的所有权就是给它发送release消息。

4、当你正在使用一个对象的时候不要release它。

以上是《Advanced Memory Management Programming Guide》中总结的规则,规则看起来很简单也很合理,用的时候只需要按照这些规则去实践就可以很好的保证合理的分配和释放内存。

所有权的策略又是基于引用计数来得以实现,即retain count。每个对象都能接受ratainCount消息返回它自身的引用计数。

1、新创建的对象的ratainCount为1;

2、发送retain消息给对象时,它的ratainCount增加1;

3、发送release消息给对象时,它的ratainCount减少1;

4、发送autorelease消息给对象时,它的ratainCount在未来某个时候减少1;

5、当ratainCount==0时,会收到dealloc消息。

重要的一点是——你实际上并不需要知道某个对象的,这个数值有时候会对你造成一些误导,因为你不知道你用到系统框架会对你关注的对象进行retain,所以在调试内存的时候只需要遵守上述的规则而不要去直接调试retainCount的值。

举一个最简单的例子:

NSObject *anObject=[[NSObject alloc] init];
NSLog("%lu",[anObject retainCount]);
[anObject release];
NSLog("%lu",[anObject retainCount]);

按照引用计数规则,第一个log会输出1——新创建的对象。

根据规则3,对象的ratainCount会减1,,但是实际的输出可能不是如此,你可以亲自的实验一下,它可能还是输出1。也可能程序在那一句上崩溃,在《Iphone开发秘籍》第二版73也中就有这个例子,是解释的崩溃。

好吧,问题来了,为什么引用计数的规则不适用了呢~这就是系统框架的原因,你可能在不同的平台上得到不同的结果,就好比GCC和Xcode里得到的结果可能不一样,我只能说可能,也可能是一样。

用一个找到的例子,说的也是这个问题 http://web2.0coder.com/archives/274

所以说,我们不需要去纠结retainCount的问题,用不上这个东西,但是回过头来看我们为了描述对象拥有和释放的规则,就非常的符合——我拥有了我创建的对象,并且我不应该在release我正在使用的对象,这样就导致了不一致的结果或者崩溃。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值