Objective-C 内存管理
2015-07-27 22:44 QiJianWan 阅读(168) 评论(0) 收藏 举报概述
开发的过程中,很多程序员都不会注意管理对象或者变量的内存,导致系统或者应用运行一段时间,就很慢了,或者崩溃。下面我们一起聊聊编程过程中的内存是如何进行管理的。
内存管理包含那些方面?
有效的内存管理,通常包含两方面内容:
内存分配:当程序创建对象时需要为对象分配内存。采用合理的设计,尽量的减少对象的创建,并减少对创建过程中的内存开销。
内存回收:当程序不再需要对象时,系统必须及时回收这些对象所占用的内存,以便程序可以再次使用这些内存。
iOS 5 之前,iOS开发人员,需要话费精力去处理内存回收相关的问题。iOS 5 之后,引入了心的特性:自动引用技术(ARC)。通过 ARC ,程序员可以不需要关注内存回收这块内容,可以大大的提高开发的效率。
Objective-C 内存回收机制有以下方式
- 手动引用计数 MRC
- 自动引用技术 ARC
手动引用计数
目前创建的项目默认都是ARC的,如何可以将项目改为 MRC 模式呢?
创建项目,打开项目的配置界面,选择 Target -> Buld Setting -> 搜索 automatic reference , 如图设置
将自动引用计数设置为NO,就可以手动引用计数了。
Objective-C 采用来一种被称为引用计数的计数来跟踪对象的状态:每个对象都有一个与之关联的整数,这个整数被称为引用计数器。正常情况下,当一段代码需要访问某个对象时,该对象的引用计数加1;当这段代码不在访问改对象时,改对象的引用计数减1,表示这段代码不在访问该对象。当对象的引用计数为0的时候,表示程序已经不在需要该对象,系统就会回收改对象所占用的内存。
系统在销毁该对象之前,会自动调用改对象的 delloc 方法来执行一些回收操作。
当对象呗销毁之后,此时该对象已经不再存在;如果有一个指针指向这个被销毁的对象,这个指针酒杯称为悬空指针,也称为野指针,僵尸指针,调用该指针指向对象的方法时,程序往往会出现未知的结果,甚至导致程序崩溃。
在手动引用计数中,改变对象的引用计数的方式如下:
- 当程序调用方法名以 alloc、new、copy、mutableCopy 开头的方法来创建对象时,该对象的引用计数加1.
- 当程序调用对象的 retain 方法时,该对象的引用计数加1.
- 当程序调用对象的 release 方式时,该对象的引用计数减1.
NSObject 中提供了有关引用计数的方法:
- retain: 引用计数+1
- release:引用计数-1
- autorelease:不改变该对象的引用计数器的值,只是将对象添加到自懂释放池中。
- retainCount:返回该对象的引用计数的值。
看看测试代码:
1 // 2 // Item.m 3 // MRC 4 // 5 // Created by 万齐鹣 on 15/7/27. 6 // Copyright (c) 2015年 万齐鹣. All rights reserved. 7 // 8 9 #import "Item.h" 10 11 @implementation Item 12 13 - (instancetype)init 14 { 15 self = [super init]; 16 if (self) { 17 NSLog(@"init方法中,引用计数为:%ld", self.retainCount); 18 } 19 return self; 20 } 21 22 -(void)dealloc 23 { 24 NSLog(@"调用销毁的方法"); 25 [super dealloc]; 26 } 27 28 @end
// // main.m // MRC // // Created by 万齐鹣 on 15/7/27. // Copyright (c) 2015年 万齐鹣. All rights reserved. // #import <Foundation/Foundation.h> #import "Item.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... Item * item = [[Item alloc] init]; // 引用计数1 NSLog(@"%ld", item.retainCount); [item retain]; // 引用计数2 NSLog(@"%ld", item.retainCount); [item retain]; // 引用计数3 NSLog(@"%ld", item.retainCount); [item release]; // 引用计数2 NSLog(@"%ld", item.retainCount); [item retain]; // 引用计数3 NSLog(@"%ld", item.retainCount); [item release]; // 引用计数2 NSLog(@"%ld", item.retainCount); [item release]; // 引用计数1 NSLog(@"%ld", item.retainCount); [item release]; // 引用计数0 } return 0; }
运行的结果:

手工内存管理规则的总结
- 如果需要保持一个对象不被销毁,可以使用 retain 。在使用完对象后,需要使用 release 进行释放。
- 给对象发送 release 消息并不会销毁这个对象,只当这个对象的引用计数减至0时,对象才会被销毁。然后系统会发送 dealloc 消息给这个对象用语释放对象。
- 对使用了 retain 或者 copy、mutableCopy、alloc 或 new 方法的任何对象,以及具有 retain 和 copy 特性的属性进行释放,需要覆盖 dealloc 方法,使得对象被释放的时候能够释放这些事例变量。
- 在自动释放池被清空时也会为自动释放的对象做些事情。系统每次都会在自动释放池被释放时发送 release 消息给池中的每个对象。如果池中的对象引用计数降为0,系统会发送 dealloc 消息销毁这个对象。
- 如果在方法中不再需要用到这个对象,但需要将其返回,可以给这个对象发送 autolease 消息用意标记这个对象延迟释放。autolease 消息并不会影响到对象的引用计数。
- 当应用终止时,内存中的所有对象都会被释放,不论它们释放在制动释放池中。
- 当开发应用程序时,随着应用程序的运行,自动释放池会被创建和清空。在这种情况下,如果要时自动释放池被清空后自动释放的对象还能够存在,对象需要使用 retain 方法,只要这些对象的引用计数大于发送 autorelease 消息的数据,就能搞在池清理后生存下来。
浙公网安备 33010602011771号