Object-C详细编程教(五)-手动内存管理

手动内存管理

有效的管理内存

1.内存分配:当程序创建对象时需要为对象分配内存。采用合理的设计,尽量减少对象的创建,并减少对创建过程中内存的开销,这是内存管理一方面的。

2.内存回收:当程序不再需要对象时,系统必须及时回收这些对象所占用的内存,以便于程序可以再次使用这些内存。

一般来说,内存分配的工作对程序影响小些,即使程序在一段时间内创建了过多的内存,造成了较大的内存开销,只要这些对象占用的内存得到了及时回收,程序依然可以正常运行。而且,内存的分配操作相对比较容易,当程序创建对象时,系统会自动的为这些对象分配内存。

相比之下,内存回收操作就显得更加复杂,管理起来也更加困难,为此,人们开发了多种内存回收策略,典型的内存回收策略有两种:

1.自动回收,在这种策略下系统会自动跟踪所有的对象,并且这些对象失去作用是回收它们占用的内存;

2.混合回收,在这种策略下,系统会做一些工作,但同时也需要程序在对象失去作用时通知系统。

     在Xcode4.2之前,Object-C内存回收需要程序员花费大量精力去理解Object-C内存回收的相关理论,而且必须在程序中通过retain、release、autorelease 方法去管理对象的引用计数,这样才能让程序正常回收内存。如果稍有不慎,程序可能会造成内存泄漏,或者可能让对象过早地被释放,从而引起程序崩溃。

     在Xcode4.2引入一个重要的新特性:自动引用计数(Automatic Reference Couting,简称ARC)。通过启用ARC特性,程序员不再需要重点关注内存回收相关的内容。在编程时使用了-fobjc-arc选项,这个选项就是启用了在Object-C的ARC机制。这样ARC机制将会自动释放对象所占用的内存。

Object-C程序员可以使用的内存回收机制有一下3种:

1.手动引用计数和自动释放池

2.自动引用计数(ARC)

3.自动垃圾回收

         只是开发Mac应用程序,甚至可以使用自动垃圾回收机制,这种机制更加方便。但,对于从事ios开发的程序员来说,自动垃圾回收机制无法使用!因为ios系统并不支持垃圾回收。ios应用目前只支持手动引用计数和ARC两种机制。相比之下,ARC已经足够简单,已用了。但如果开发者需要开发一些兼容更早ios平台的应用,只能用手动引用计数。

     对象的引用计数

    程序创建一个对象时,可能在一段时间内访问该对象的实例变量,也可能在这段时间内调用该对象的方法。当程序不再需要改对象时,就希望系统及时回收改对象所占用的内存。现在的问题是:系统怎么知道何时需要回收该对象?

    Object—C采用了一种称为引用计数(Reference Counting)的机制来跟踪对象的状态:每个对象都有一个与之关联的整数,这个整数被称为引用计数器。正常情况下,当一段代码需要访问某个对象时,改对象的引用计数加1;当这段代码不在访问该对象时,该对象的引用计数减1,当对象的引用计数为0时,表示程序已经不再需要该对象,系统就会回收该对象所占的内存。

   系统在销毁该对象前,会自动调用该对象的dealloc方法来执行一些回收操作,比如该对象还持有其他对象的引用,此时必须重写dealloc方法。在该方法中释放该对象所持有的其他对象(通常就是调用被持有对象的release方法将引用计数减1)。

    当对象被销毁之后(它的引用计数变为0,并且系统会自动调用了该对象的dealloc方法),此时该对象已经不再存在;如果有一个指针指向这个被销毁的对象,这个指针就被称作为悬空指针(Dangling Pointer),调用悬空指针指向对象的方法时,程序往往会出现未知结果,甚至导致程序崩溃。程序员千万别主动去调用对象的dealloc方法!当一个对象的计数为0时,系统会自动调用该对象的dealloc方法来销毁它。

在手动引用计数中,改变对象的引用计数的方法:

  • 当程序调用方法名以alloc、new、copy、mutableCopy开头的方法来创建对象时,该对象的引用计数加1。方法名都是指以驼峰写法(每个单词首字母大写,单词与单词之间无需任何分隔符)开头的,比如newBook的方法会导致引用计数加1,但名为newyork(字母y没有大写)的方法则不会导致加1.
  • 程序调用对象的retain时,该对象引用计数加1.
  • 程序调用该对象的release方法时,该对象引用计数减1.
    NSObject中提供了有关引用计数的如下方法:

  • -retain:将该对象的关引用计数加1
  • -release:将该对象的关引用计数减1
  • -autorelease:不改变该对象的计数器值,自是将对象添加到自动释放池中。
  • -retainCount:返回该对象的引用计数的值
   使用自动释放池

如果在函数、方法开始处将对象的引用计数加1,接下来在函数、方法不需要该对象时就应该将该对象的引用计数减1.这个理论上基本正确,可问题在于,有些函数。方法需要返回一个对象:该函数、方法需要返回的对象肯定不能立即将引用计数减1,这样系统可能在该对象被返回前,已经销毁了对象。

为了保证函数、方法返回的对象不会再被返回前就被销毁,我们就需要保证被函数、方法返回的对象能被延迟销毁。为了实现这种延迟销毁,有如下2种做法:

  1. 程序每次获取并使用完其他的方法、函数返回的对象之后,立即调用该对象的release方法将函数、方法返回对象的引用计数减1.
  2. 使用自动释放池进行延迟销毁。
第一种比较容易理解,但,便呈现的比较复杂。

例如,如下程序:

#import <Foundation/Foundation.h>
#import "FKItem.h"
FKItem* productItem()
{
FKItem* item = [FKItem new];//引用计数为1
NSLog (@"函数返回之前的引用计数: %ld",item.retainCount);//返回的对象的引用计数为1
return item;

}
int main(int argc,char * argv[])
{
//it的引用计数为1
FKItem* it =productItem();
//接下来可以调用it的方法
NSLong(@"%ld" , it.retainCount);
//...
//程序执行完成后,将it(引用productItem()函数返回值)的引用计数减1
//程序使用productItem()函数返回值完成后,延迟销毁it所指向的对象
[it release];


}
    上面的做法虽然简单易懂,但与前面介绍的原则违背:谁负责将对象的引用计数加1,谁就应该负责将该对象的引用计数减1.更好的做法是用自动释放池来解决这个问题。

自动释放池,是指它是一个存放对象的容器(比如集合),而自动释放池会保证延迟释放该池中的所有对象。





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值