[Note] Effective OC - Item 32~36

Chapter 5. Memory Management

<br />


Item 32: Beware of Memory Management with Exception-Safe Code

<br />
这一节讲的是使用exception时存在的内存管理问题。
在Item21讲NSError的使用时已经提到了,OC的设计并不是exception-safe的,因此不能普遍地使用exception,而只应该在发生严重问题的时候才用。大多数情况使用NSError是更好地选择。
具体来说,在手动管理引用计数的时候,避免内存泄露的写法是这样的:

EOCSomeClass *object;
@try {
   object = [[EOCSomeClass alloc] init];
   [object doSomethingThatMayThrow];
}
@catch (…) {
   NSLog(@“error occurred”);
}
@finally {
   [object release];
}

关键在于要添加一个@finally块,这是一个不管是否抛出异常都会到达的块,所以把release放在这里,保证object的释放。如果没有这个块,把release放在@try里,那么如果释放前抛出了异常,释放这一句就不会被调用,内存泄露就会产生。
如果在ARC环境,release就不能手动调用了。但需要注意的是,和普通情况不同,此时系统默认情况下也不会自动帮我们调用,必须开启-fobjc-arc-exceptions编译器标志以后,ARC才可以生成这种情况下的附加代码。但是会一定程度影响运行效率。
<br />


Item 33: Use Weak References to Avoid Retain Cycles

<br />
这一节讲用弱引用打破保留环。
篇幅比较短,内容我也比较熟悉,好像没有什么特别要记下来的。实际中最常见的场景就是用block的时候要小心,什么时候需要定义weakSelf。如果block直接对self引用比较容易看出来,但是环里有两个以上的对象的时候就不是很容易看出来,比如block里引用了一个已经引用self的对象。
__unsafe_unretained和__weak都能有打破环的效果,因为都并不保留对象,但是因为存在野指针的问题,__weak是更推荐的做法,更安全。
<br />


Item 34: User Autorelease Pool Blocks to Reduce High-Memory Waterline

<br />
这一节讲通过新建autorelease pool来压低内存的峰值。
“The high-memory waterline refers to the highest memory footprint of an application during a certain period.” 一开始不太懂这个waterline到底指的什么,根据这句理解是程序运行中的内存峰值。
如果对对象调用autorelease而不是release,就会使对象多存活一段时间,到下一个event loop才会调用一次release,这里是指只是用系统自带的那个写在main函数的自动释放池的情况。但是如果所有的对象都等到这时再释放,内存就会一直积累,峰值就会很高。为了避免这种情况,当出现占用内存多但是又可以用完就释放的对象时,可以手动创建一个自动释放池来使它提前释放,比如这样:

NSArray *databaseRecords = /*…*/
NSMutableArray *people = [NSMutableArray new];
for (NSDictionary *record in databaseRecords) {
    @autoreleasepool {
       EOCPerson *person = [[EOCPerson alloc] initWithRecord:record];
       [people addObject:person];
    }
}

这个场景假设的是需要新建的person对象非常多。如果不采用自动释放池,这些新建的person对象就会一直存在到下一个event loop,而采用这种写法以后,在这个自动释放池的末尾这些临时对象就可以被回收了,这样内存峰值就及时降下来了。
<br />


Item 35: Use Zombies to Help Debug Memory-Management Problems

<br />
这一节讲的是用Zombie Objects来调试程序。
这个东西我不太熟悉,也没有见过。不过原理还是比较好理解。对象在被释放以后,原来存放对象的那块内存会被标记为“可重用”,这样就可以重新被分配做他用了。但是这个过程不是立即执行的,具体什么时候执行并不能确定。所以这块内存可能仍有东西在占用,如果给它发消息有时甚至还能相应,但是不一定是我们希望的那个对象的响应,这样就会有奇怪的Bug出现。而比较理想的情况是,一旦内存被释放了,不管有没有被重新用掉,我们都能得知这一信息,如果给它发消息,能提示我们是在给已经释放的对象发消息,利于我们调试。
Zombie Object就能实现这一功能。默认是不打开NSZombieEnabled环境变量的,怎么打开文中写了,我找了一下,真的有诶←_←。

僵尸对象的原理是,在NSObject执行dealloc时,如果发现打开了NSZombieEnabled环境变量,就通过method swizzling(Item13有讲过)把dealloc的代码变了,多加了一部分,不仅把对象所属的类变成NSZombie了,而且还自动加上了原类名作为后缀,就像_NSZombie_OriginalClassName这种形式。此时如果再向这个对象发送消息,程序会判断消息的接收者的类型,如果是以NSZombie为前缀,就不会执行这个消息,而是打印一条错误的信息出来,提示“message sent to deallocated instance”,并且会显示对象销毁前的类名。
使用Zombie Object是不会把内存释放的,只是把需要释放的内存改了所属类。但是只是在调试时会使用,所以不会引起实际的效率问题。
<br />


Item 36: Avoid Using retainCount

<br />
用了整整一节来嫌弃retainCount这个方法...
结论就是永远都不要用。原因的话,其实这个方法的reference已经写的比较明白了:

This method is of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.

总的来说,就是因为引用计数是一个非常动态的过程,特别是有自动释放池存在的情况下,计数的增减有实际意义,而绝对值并没有实际意义。不过文中给了更为详细例子。比如有时系统会做优化,对象在引用计数为1时就可能被回收。再比如,单例对象的引用计数永远都很大而且不变。再比如,某个调用方法内部可能自行保留或者释放了对象,而外面看不出来,使得到的结果和想象得不一致。所以调用这个方法得不到任何有效的信息,结论就是,永远不要用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容