iOS内存管理(一)


1. <wbr>内总管理原则(引用计数)<br></wbr><wbr><wbr> IOS的对象都继承于NSObject, <wbr> 该对象有一个方法:retainCount ,内存引用计数。 引用计数在很多技术都用到: window下的COM组件,多线程的信号量,读写锁,思想都一样。<br><wbr><wbr><wbr><br><wbr><wbr>(一般情况下: 后面会讨论例外情况)<br><wbr><wbr> alloc <wbr><wbr><wbr>对象分配后引用计数为1<br><wbr><wbr> retain <wbr><wbr>对象的引用计数+1<br><wbr><wbr> copy <wbr><wbr><wbr>copy 一个对象变成新的对象(新内存地址) 引用计数为1 原来对象计数不变<br><wbr><wbr><br><wbr><wbr> release <wbr><wbr><wbr><wbr><wbr><wbr>对象引用计数-1 如果为0释放内存<br><wbr><wbr> autorelease <wbr><wbr><wbr>对象引用计数-1 如果为0不马上释放,最近一个个pool时释放<wbr><wbr><wbr><br><span style="white-space: pre;"><span style="white-space: normal;"><span style="color: rgb(61, 34, 127);">NSLog</span></span><span style="font-family: Menlo;">(</span><span style="font-family: Menlo;">@"sMessage retainCount:%u"</span><span style="font-family: Menlo;">,[sMessage<wbr></wbr></span><span style="font-family: Menlo;"><span style="color: rgb(61, 34, 127);">retainCount</span></span><span style="font-family: Menlo;">]);</span></span><span style="white-space: pre;"><br></span><span style="white-space: pre;">[sMessage <span style="color: rgb(61, 34, 127);">retain</span>]; //2</span><br><span style="color: rgb(61, 34, 127);">NSLog</span>(@"sMessage retainCount:%u",[sMessage<wbr><span style="color: rgb(61, 34, 127);">retainCount</span>]);<br><span style="color: rgb(61, 34, 127);">NSLog</span>(@"sMessage retainCount:%u",[sMessage<wbr><span style="color: rgb(61, 34, 127);">retainCount</span>]);<br><span style="font-family: Menlo;"><span style="color: rgb(61, 34, 127);">NSLog</span></span><span style="font-family: Menlo;">(</span><span style="font-family: Menlo;">@"sMessage retainCount:%u"</span><span style="font-family: Menlo;">,[sMessage</span><wbr><span style="font-family: Menlo;"><span style="color: rgb(61, 34, 127);">retainCount</span></span><span style="font-family: Menlo;">]);</span><br><wbr><wbr> 内存管理的原则就是最终的引用计数要平衡,<br><span style="color: rgb(255, 0, 0);"><wbr><wbr>如果最后引用计数大于0 <wbr>则会内存泄露</wbr></wbr></wbr></span><br><span style="color: rgb(255, 0, 0);"><wbr><wbr>如果引用 计数等于0还对该对象进行操作,则会出现内存访问失败,crash <wbr><wbr>所以尽量设置为nil</wbr></wbr></wbr></wbr></span><br><wbr><wbr><br><wbr><wbr>这两个问题都很严重,所以请一定注意内存释放和不用过后设置为nil<br><strong>2. autoReleasePool</strong><br><wbr><wbr>每个工程都有一个 main.m 文件: 内容如下:<br><wbr><wbr>int main(int argc, char *argv[]) {<br><span style="font-family: Arial; line-height: 26px; color: rgb(51, 51, 51);"><wbr><wbr><wbr></wbr></wbr></wbr></span><br><span style="font-family: Arial; line-height: 26px; color: rgb(51, 51, 51);"><wbr><wbr><wbr> NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];</wbr></wbr></wbr></span><br><span style="font-family: Arial; line-height: 26px; color: rgb(51, 51, 51);"><wbr><wbr><wbr> int retVal = UIApplicationMain(argc, argv, nil, nil);</wbr></wbr></wbr></span><br><span style="font-family: Arial; line-height: 26px; color: rgb(51, 51, 51);"><wbr><wbr><wbr> [pool release];</wbr></wbr></wbr></span><br><span style="font-family: Arial; line-height: 26px; color: rgb(51, 51, 51);"><wbr><wbr><wbr> return retVal;</wbr></wbr></wbr></span><br><span style="font-family: Arial; line-height: 26px; color: rgb(51, 51, 51);">}</span><br><wbr><wbr>很明显C语言的main 函数:<wbr><br><wbr> NSAutoreleasePool 是用来做autorelease 变量释放的,前面说了, autorelease不会马上释放,当他到了最近的pool release 时会检查reatin count 是不是为0, 为0就释放。<wbr><br> 当我们在一段代码时加入了大量的autorelease变量时,我们应该为这段代码加上<br> Autoreleasepool,其它时候不用<br> 在返回一个对象时常常要返回一个autorelease 对象,因为objectC 对象都是动态内存,没有<br> 栈的概念,所以不能像C/C++一样返回一个对象到栈,只能用autorelease对象。<br><strong>3. 成员变量与属性</strong><br><wbr><wbr> 实际情况并非上面那么简单,你可能需要在一个函数里调用另一个函数分配的变量这时候<br> 有两个选择: <wbr>类成员变量和使用属性<br><wbr><wbr>@interface TestMem: NSObject {<br><wbr><wbr><wbr><wbr><wbr><wbr> TestObject <wbr> *m_testObject<wbr>; <wbr><wbr><wbr><wbr><wbr><wbr>// 成员变量<br><wbr><wbr><wbr><wbr><wbr><wbr> TestObject <wbr> *testObject; <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> //成员变量<br><wbr><wbr> }<br><wbr>成员变量与上面的内存管理是一致的,只是在不同的函数里要保持引用计数加减的平衡<br> 所以要你要每次分配的时候检查是否上次已经分配了。是否还能调用<wbr><br> 什么时候用属性?<br><wbr> 1. 把成员做为public.<br><wbr> 2. outlet 一般声明为属性( 这个内存于系统控制,但我们还是应该做一样操作,后面会讲)<br><wbr> 3. 如果很多函数都需要改变这个对象 ,或这个函数会触发很多次,建议使用属性。我们看看属性函数展开后是什么样子:<br><br> // assign<br> -(void)setTestObject :(id)newValue{<br><wbr><wbr><wbr>testObject= newValue;<br> }<br> // retain<br> -(void)setTestObject <wbr>:(id)newValue{<br><wbr><wbr><wbr> if (testObject!= newValue) {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [testObject release];<br><wbr><wbr><wbr><wbr><wbr>testObject= [newValue retain];<br><wbr><wbr><wbr> }<wbr><br> }<br> // copy<br> -(void)setTestObject :(id)newValue{<br><wbr><wbr><wbr> if (testObject<wbr>!= newValue) {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [testObject<wbr>release];<br><wbr><wbr><wbr><wbr><wbr>testObject<wbr>= [newValue copy];<br><wbr><wbr><wbr> }<br> }<br> asssign 相于于指针赋值,不对引用计数进行操作,注意原对象不用了,一定要把这个设置为nil<br> retain 相当于对原对象的引用计数加1<br> copy 不对原对象的引用计数改变,生成一个新对象引用计数为1<br> 注意:<br><wbr> self.testObject 左值调用的是setTestObject 方法. 右值为get方法,get 方法比较简单不用说了<br><wbr> 而 真接testObject 使用的是成员变量<br><wbr> self.testObject = [[testObject alloc] init]; <wbr> // 错 <wbr>reatin 两次<br><wbr> testObject = <wbr> [NSArray objectbyindex:0]; <wbr><a>//错</a><wbr>不安全,没有retain 后面release会出错<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> 如果testObject已有值也会mem leak <wbr><wbr><wbr><wbr><br><strong>4. 自动管理对象</strong><br><wbr><wbr>IOS 提供了很多static(+) 创建对象的类方法,这些方面是静态的,可以直接用类名<br> 调用如:<br><wbr><wbr>NSString *testString = [NSString stringWithFormat:@"test" ];<br><wbr><wbr>testString 是自动管理的对象,你不用relese 他,他有一个很大的retain count,<wbr>release后数字不变。<br><wbr><wbr><br><strong>5. 例外</strong><br><wbr><wbr>有一些通过alloc 生成的对象相同是自动管理的如:<br><wbr><wbr>NSString <wbr>*testString <wbr>= [[NSString alloc]<wbr>initWithString:@"test1"];<br><wbr><wbr>retain count 同样是很大的数,没办法release<br><wbr><wbr>但为了代码对应,还是应该加上[ testString release];<br><wbr><wbr>不然xcode的Analyze 会认识内存leak, 但Instruments leak 工具检测是没有的<br><strong>6.view <wbr>内存管理</wbr></strong><br><wbr><wbr>通常我们编程会用到view, <wbr> 在view 中的方法:<br><wbr><wbr><br><wbr> viewDidload<wbr><br><wbr><wbr>didReceiveMemoryWarning<wbr><br><wbr>viewDidUnload<wbr><br><span style="font-family: Menlo; color: rgb(255, 81, 133);">@property (retain) NSArray *iarrTestMem</span><br><span style="font-family: Menlo; color: rgb(255, 81, 133);"><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></span><br><span style="font-family: Menlo; color: rgb(255, 81, 133);"><wbr><wbr><wbr><wbr> viewDidLoad</wbr></wbr></wbr></wbr></span><br><span style="font-family: Menlo; color: rgb(255, 81, 133);"><wbr><wbr><wbr><wbr><wbr><wbr> init retain is <wbr><wbr><wbr><wbr> 0</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></span><br><span style="font-family: Menlo; color: rgb(255, 81, 133);"><wbr><wbr><wbr><wbr><wbr><wbr> (alloc) <wbr><wbr><wbr><wbr><wbr><wbr><wbr> +1<wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></span><span style="font-family: Menlo; color: rgb(255, 81, 133);">=1</span><br><span style="font-family: Menlo; color: rgb(255, 81, 133);"><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></span><br><span style="font-family: Menlo; color: rgb(255, 81, 133);"><wbr><wbr><wbr><wbr><wbr>if(memwarning)</wbr></wbr></wbr></wbr></wbr></span><br><span style="font-family: Menlo; color: rgb(255, 81, 133);"><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> didrecivememwarning <wbr>-0<wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></span><span style="font-family: Menlo; color: rgb(255, 81, 133);">=1</span><br><span style="font-family: Menlo; color: rgb(255, 81, 133);"><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></span></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值