iOS夯实:内存管理
iOS夯实:内存管理
文章转自 内存管理
最近的学习计划是将iOS的机制原理好好重新打磨学习一下,总结和加入自己的思考。
有不正确的地方,多多指正。
目录:
基本信息
Objective-C 提供了两种内存管理方式。
MRR (manual retain-release) 手动内存管理
这是基于reference counting实现的,由NSObject与runtime environment共同工作实现。ARC (Automatic Reference Counting)自动引用技术
ARC使用了基于MBR同样的reference counting机制,区别在于系统在编译的时候帮助我们插入了合适的memory management method。
Good Practices能有效的避免内存相关问题
基于内存,主要有两种错误
- 清空或覆盖了还在使用的内存
这种清空通常会导致应用崩溃,甚至用户数据遭到改写 - 没有清空已经不需要的内存会导致内存泄露
会导致系统性能下降,应用遭到系统终止
实际上,我们不应该只从reference counting的角度来管理内存,这样会让我们纠结于底层细节。我们应该站在object ownership and object graphs的角度来管理内存
可以用一幅这样的图来阐明:

旧时代的细节
一.基本内存管理准则
基本的内存管理准则:Cocoa为我们提供了这些准则
You own any object you create
我们通过名字前缀为“alloc”, “new”, “copy”, or “mutableCopy”的方法创建对象You can take ownership of an object using retain
通过retain来获取对象的ownership,使用retain主要有两种场景- 在accessor method 或 init method。来获取你想存储的对象的所有权
- 在某些场景里避免一个对象被移除,我们可以对它进行retain
When you no longer need it, you must relinquish ownership of an object you own
当我们需要释放一个对象所有权时,我们通过对它发送release或autorelaese消息。You must not relinquish ownership of an object you do not own
不要释放你没有拥有的对象所有权
关于dealloc:
NSObject为我们提供了一个dealloc方法,当对象被销毁时,系统会自动调用它。这个方法的作用主要是清空对象自身内存与它所持有的资源。例如:
@interface Person : NSObject
@property (retain) NSString *firstName;
@property (retain) NSString *lastName;
@property (assign, readonly) NSString *fullName;
@end
@implementation Person
- (void)dealloc
[_firstName release];
[_lastName release];
[super dealloc];
}
@end
需要强调的是:永远不要自己调用dealloc方法
在dealloc的最后需要调用super class的dealloc
二.实践中的内存管理准则
1. 使用存取方法来简化内存管理。
如果代码中都是一堆retain release,必然不是一个好的情况。在存取方法里面进行retain和release的操作能够简化内存管理。例如:
- (void)setCount:(NSNumber *)newCount {
[newCount retain];
[_count release];
// Make the new assignment.
_count = newCount;
}
2. 使用存取方法来设置Property value
对比如下代码,第一种使用了存取方法来设置,第二种直接对实例变量操作。显然我们应该采用第一种,使用第二种情况,简单的情况还好,如果情况一旦复杂,就非常容易出错。并且直接对实例变量操作,不会引发KVO通知。
- (void)reset {
NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
[self setCount:zero];
[zero release];
}
- (void)reset {
NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
[_count release];
_count = zero;
}
3. 不要在初始化方法和dealloc方法中使用Accessor Methods
苹果在《Advanced Memory Management Programming Guide》指出:
Don’t Use Accessor Methods in Initializer Methods and dealloc The only places you shouldn’t use accessor methods to set an instance variable are in initializer methods and dealloc. To initialize a counter object with a number object representing zero, you might implement an init method as follows:
- init {
self = [super init];
if (self) {
_count = [[NSNumber alloc] initWithInteger:0];
}
return self;
}
唯一不需要使用Accessor Methods的地方是initializer和dealloc. 在苹果官方文档中没有解释为什么。经过一番查阅后,最主要的原因是此时对象的状况不确定,尚未完全初始化完毕,而导致一些问题的发生。
例如这个类或者子类重写了setMethod,里面调用了其他一些数据或方法,而这些数据和方法需要一个已经完全初始化好的对象。而在init中,对象的状态是不确定的。
举个例子,一个子类重写了set方法,在里面进行了一些子类特有的操作,而此时如果父类在init直接使用Accessor Methods,就会导致问题的发送。
其它一些问题还有,像会触发KVO notification等。[^1] [^2]
总之,记住在开发中记住这个principle最重要。
在开发中,我发现还是有人因为疏忽或不知道而直接在init方法里面使用self.property = XXX来进行赋值,留下了一些隐患。Swift去除了直接和instance variable打交道的途径。统一使用property进行管理,并对init进行严格的规定,提升了安全性,解决了人为因素导致的错误。欢迎对Swift有兴趣的同学继续阅读。从Objective-C到Swift
[^1]: stackoverflow [^2]: objc-zen-book
4. 使用弱引用来避免引用环
我们都知道在ARC,弱引用通过声明property的attribute为weak来实现。
而在MRR中则是通过引用对象,但是不retain它来实现(A weak reference is a non-owning relationship where the source object does not retain the object to which it has a reference)
在Cocoa中,典型需要使用弱引用的有delegate,data source, notification observer
我们需要注意处理好弱引用对象,如果对已经被销毁的对象发送信息,则会导致crash.通常被弱引用的对象当它将被销毁时,负责通知其它object.
像notification center保存了observer的弱引用,因此当被弱引用observer准备结束生命周期时,observer需要通知notification center,unregister自己。
4. 不要让你正在使用的对象被移除
观察以下两种代码,第一种因为没有retain,对象可能会被移除,而第二种是正确的写法
heisenObject = [array objectAtIndex:n];
[array removeObjectAtIndex:n];
// heisenObject could now be invalid. heisenObject = [[array objectAtIndex:n] retain];
[array removeObjectAtIndex:n];
// Use heisenObject...
[heisenObject release];
5. Collections类拥有其收集的的对象的所有权
例如NSArray,dictionary等。他们负责其收集的对象的所有权,因此我们不需要retain存进去的对象。 例如下面的allocedNumber就不需要retain了。
for (i = 0; i < 10; i++) {
NSNumber *allocedNumber = [[NSNumber alloc] initWithInteger:i];
[array addObject:allocedNumber];
[allocedNumber release];
}
6. 最后,以上这些ownership policy是基于retain count实现的
- 当你创建一个对象,它的retain count为1。
- 当你对一个对象发送retain信息,它的retain count +1
- 当你对一个对象发送release信息,他的retain count -1
当你对一个对象发送autorelease信息,在当前autorelease pool block结束时,retain count -1 - 当一个对象的retain count 降至0,它就被dealloced了。
三.使用Autorelease Pool block
autorelease pool 为我们提供了一个机制,避免当我们解除一个对象所有权时,对象被立刻销毁(例如从一个方法里返回一个对象)
一个autorelease pool block对象是这样子的:
@autoreleasepool {
// Code that creates autoreleased objects.
}
在block的最后,所有收到过autorelease消息的对象都会接收到release消息。
在ARC的新时代里面,autorelease pool block主要用于处理避免内存峰值,只是我们不需要再手动添加autorelease的代码了
例如以下这个例子(有点生编硬造,主要为了阐明一下)
如果我们没有添加autoreleasepool,我们最后可需要释放10000*10000个对象,而不是每次循环都分别释放掉10000个对象
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
@autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(@"number = %p", number);
}
}
}
}
新时代
详情亲看:iOS夯实:ARC时代的内存管理
iOS夯实:内存管理的更多相关文章
- 理解 iOS 的内存管理
远古时代的故事 那些经历过手工管理内存(MRC)时代的人们,一定对 iOS 开发中的内存管理记忆犹新.那个时候大约是 2010 年,国内 iOS 开发刚刚兴起,tinyfool 大叔的大名已经如雷贯耳 ...
- iOS ARC内存管理
iOS的内存管理机制,只要是iOS开发者,不管多长的时间经验,都能说出来一点,但是要深入的理解.还是不简单的.随着ARC(自动管理内存)的流行.iOS开发者告别了手动管理内存的复杂工作.但是自动管理内 ...
- iOS之内存管理(ARC)
iOS的内存管理,相信大家都不陌生,之前是使用的MRC,由开发人员手动来管理内存,后来使用了ARC,来由系统管理内存.本文主要讲讲Autorelease,Core Foundation对象在内存管理方 ...
- 说说iOS与内存管理(上)
http://www.cocoachina.com/ios/20150625/12234.html 说起内存管理,看似老生常谈,而真正掌握内存管理的核心其实并不简单.ARC/MRR以及“谁分配谁就负责 ...
- iOS的内存管理和引用计数规则、Block的用法以及三种形式(stack、malloc、global)
学习内容 iOS的内存管理和引用计数规则 内存管理的思考方式 自己生成的对象自己持有 非自己生成的对象自己也能持有 自己持有的对象不需要时释放 非自己持有的对象不能释放 ARC有效时,id类型和对象类 ...
- iOS - OC 内存管理
1.OC 基本内存管理模型 1.1 自动垃圾收集 在 OC 2.0 中,有一种称为垃圾收集的内存管理形式.通过垃圾收集,系统能够自动监测对象是否拥有其他的对象,当程序执行需要空间的时候,不再被引用的对 ...
- 总结 IOS 7 内存管理
[iOS7的一些总结].iOS中的内存管理 我们知道,为了更加方便地处理内存管理问题,将开发人员从繁琐的内存的分配和释放工作中解放出来而专注于产品和逻辑,iOS提供了一种有效的方法, 即自动引用计数A ...
- iOS的内存管理
在Objective-C 这种面向对象的语言里,内存管理是个重要的概念.要想用一门语言写出内存使用效率高而且又没有bug的代码,就得掌握其内存管理模型的种种细节. 一旦理解了这些规则,你就会发现,其实 ...
- IOS ARC内存管理,提高效率避免内存泄露
本文转载至 http://blog.csdn.net/allison162004/article/details/38756263 Cocoa内存管理机制 (1)当你使用new.alloc.copy方 ...
- 【iOS系列】-iOS中内存管理
iOS中创建对象的步骤: 1,分配内存空间,存储对象 2,初始化成员变量 3,返回对象的指针地址 第一:非ARC机制: 1,对象在创建完成的同时,内部会自动创建一个引用计数器,是系统用来判断是否回收对 ...
随机推荐
- 在Linux下怎么确定哪个网卡对应哪个接口?
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...
- 部署应用程序脚本+GUIRunOnce命令
部署应用程序脚本: 应用程序配置:运行脚本(cmd.exe): 可执行程序:cmd.exe 参数: /c net user ppc boc.123 /add 运行方式账户: NT AUT ...
- MX记录查询
nslookup set type=mx
- Codeforces Round #318 [RussianCodeCup Thanks-Round] (Div. 1) A. Bear and Poker 分解
A. Bear and Poker Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/573/pro ...
- Bump mapping的GLSL实现 [转]
原文 http://www.cnblogs.com/CGDeveloper/archive/2008/07/03/1234206.html 如果物体表面细节很多,我们可以不断的精细化物体的几何数据,但 ...
- QProcess调用外部程序方式的差异
众所周知QProcess类的作用是启动一个外部的程序并与之交互它有三种方式调用外部程序: 1. execute 2. start 3. startDetached 从调用上看: execute是阻塞调 ...
- windows 下的命令行工具。。
1.powershell window自带..右下角搜索..powershell 2.conemu https://code.google.com/p/conemu-maximus5/wiki/Dow ...
- aptana中删除空行
问题:有一个css文件,写一行样式后,会换行,空一行,再写另一个样式.现在需要把空的一行给去掉. 尝试直接复制空行,但是aptana会把所有的换行都去了,变成了一个文件只有一行.尝试用正则,\r\t\ ...
- zookeeper-3.4.6安装
下载zookeeper包并解压 配置.在conf文件夹中将zoo_sample.cfg复制一份为zoo.cfg 修改zoo.cfg 在/home/admln/zookeeper中新建一个文件myid( ...
- github使用成长记
学校里一直都有自己写一些网页,一方面为了学习熟练技能,另一方面也是兴趣所在.但是独乐乐不如众乐乐,一直向往有那么一个平台能把自己做得东西分享给广大网友,并且想借着分享的契机和各位程序猿交流学习心得(这 ...