ios內(nèi)存管理(六):異常安全與內(nèi)存管理

??前面幾節(jié)主要從對(duì)象在內(nèi)存中的生命周期這個(gè)角度,梳理了一下objc的內(nèi)存管理特性。接下來說幾個(gè)和內(nèi)存管理有密切關(guān)系的語(yǔ)言特性。

??本節(jié)主要看一下objc的異常處理部分。我們都知道objc也提供了try-catch機(jī)制,但是在實(shí)際開發(fā)中卻很少使用到,這是為什么呢?

??為了方便說明問題,先不考慮ARC,假設(shè)在非ARC模式下,有如下代碼:

  @try {
        ClassTest *t = [ClassTest alloc] init];
        // 此函數(shù)可能會(huì)拋出異常
        [t doSomethingMayThrowException];
        [t release];
  }
  @catch(NSException *e) {
        NSLog(@"Oops, there was an exception");
  }

??上面的代碼會(huì)產(chǎn)生什么問題嗎?按照try-catch的邏輯,如果在方法doSomethingMayThrowException執(zhí)行時(shí)真的拋出異常,try塊的代碼執(zhí)行會(huì)終止,程序跳轉(zhuǎn)到catch部分,那么實(shí)例t的release方法就不會(huì)被執(zhí)行,從而造成內(nèi)存泄露。

??當(dāng)然,這個(gè)問題也有解決方式,就是補(bǔ)充finally塊來釋放對(duì)象,保證對(duì)象一定會(huì)被釋放,如下:

  ClassTest *t;
  @try {
        t = [ClassTest alloc] init];
        // 此函數(shù)可能會(huì)拋出異常
        [t doSomethingMayThrowException];
  }
  @catch(NSException *e) {
        NSLog(@"Oops, there was an exception");
  }
  @finally {
        [t release];
  }

??為了在finally塊里面引用t對(duì)象,首先需要將t的定義挪到try塊外面,由于本示例中只有一個(gè)對(duì)象,所以感覺還不是特別麻煩。想象一下在實(shí)際的工程中,所有的對(duì)象都需要這樣實(shí)現(xiàn),是不是感覺還是十分頭疼的。而且,隨著代碼量的增加,很容易就忘記釋放某個(gè)對(duì)象,就會(huì)導(dǎo)致內(nèi)存泄露。若泄露的對(duì)象是文件描述符或數(shù)據(jù)庫(kù)連接之類的稀缺資源,就可能導(dǎo)致比較大的問題。如果try塊里面的代碼又有try-catch嵌套,那問題就更麻煩了。

??上面說的是非ARC環(huán)境,那么在ARC環(huán)境下怎么樣呢?系統(tǒng)會(huì)不會(huì)幫我們搞定了一切,我們只需要放心使用就可以了呢?很遺憾,不是。在ARC環(huán)境下,問題反而更嚴(yán)重了,因?yàn)椴荒茉偈謩?dòng)調(diào)用release了,所以無法在finally塊里面手動(dòng)實(shí)現(xiàn)release,必然會(huì)造成內(nèi)存泄露。

??為什么ARC不自動(dòng)去處理這些內(nèi)存管理問題?主要是從性能角度去考慮。前面的幾個(gè)章節(jié)介紹過,ARC并非是objc的一個(gè)語(yǔ)言特性,而是一個(gè)編譯器福利,即使打開ARC,objc的內(nèi)存管理還是通過引用計(jì)數(shù)去實(shí)現(xiàn),只是編譯器在編譯時(shí),自動(dòng)幫用戶插入了retain、release等調(diào)用代碼。那么對(duì)于try-catch機(jī)制來說,要想自動(dòng)處理好內(nèi)存管理,在try塊開始之前要保存所有塊中的變量,這樣做需要插入大量的樣板代碼,以便跟蹤待清理的對(duì)象,從而在拋出異常時(shí)將其釋放。為了達(dá)到這個(gè)目的,付出的代價(jià)就是運(yùn)行期性能的降低,以及添加進(jìn)來的大量的額外代碼會(huì)明顯增加應(yīng)用程序的大小。因此,默認(rèn)情況下ARC是不會(huì)對(duì)try-catch機(jī)制有特殊處理的。關(guān)于try-catch的實(shí)現(xiàn)比較復(fù)雜,可以參考源代碼https://opensource.apple.com/source/objc4objc-exception.mm等實(shí)現(xiàn)文件幫助理解。

??雖然默認(rèn)情況下ARC不會(huì)自動(dòng)處理try-ctach代碼塊,但蘋果也為用戶提供了這種能力:就是-fobjc-arc-exceptions選項(xiàng)。打開這個(gè)編譯器標(biāo)志可以在ARC模式下較好的處理try-catch的內(nèi)存管理問題,代價(jià)就是性能的下降以及程序體積的上升,而且這也并不意味著所有的問題都會(huì)被正確的處理。

??也是基于以上這些原因,在objc的中比較少使用到try-catch機(jī)制。通常只有當(dāng)應(yīng)用程序必須因異常狀況而終止時(shí)才使用,這時(shí)由于應(yīng)用程序即將終止,即使發(fā)生內(nèi)存泄露也無關(guān)緊要了。而在其他場(chǎng)景下,可以使用NSError機(jī)制來處理程序錯(cuò)誤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 29.理解引用計(jì)數(shù) Objective-C語(yǔ)言使用引用計(jì)數(shù)來管理內(nèi)存,也就是說,每個(gè)對(duì)象都有個(gè)可以遞增或遞減的計(jì)數(shù)...
    Code_Ninja閱讀 1,753評(píng)論 1 3
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,656評(píng)論 30 472
  • 學(xué)問之道在求其放心 余超林晨讀《孟子》感言集之二 “孟子曰:‘仁,人心也。義,人路也。舍其路而弗由,...
    余超林AIA財(cái)富管家閱讀 1,513評(píng)論 0 1
  • 每當(dāng)夜晚來臨的時(shí)候,仔細(xì)端詳自己的生活和工作的時(shí)候,我的內(nèi)心里總是充滿了不安和焦慮,一種隱隱約約的痛涌上心頭。30...
    公子義閱讀 2,462評(píng)論 0 2
  • 之前聽一個(gè)行業(yè)前輩說,曾經(jīng)輝煌的BAT里,B已經(jīng)開始消失了。不過在今天參加過B的產(chǎn)品運(yùn)營(yíng)面試后,我仍覺得B的職員還...
    jonuson大雄閱讀 1,825評(píng)論 1 0

友情鏈接更多精彩內(nèi)容