說明:本文為學習筆記匆笤,參考書籍《Objective-C高級編程ios與osx多線程與內存管理》,僅供自我學習。
大家看到內存的第一反應就會想到自動引用計數(shù)俘闯,其實引用計數(shù)式內存管理僅僅是思考方式而已。我們需要理解4個詞“生成”“持有”“釋放”“銷毀”忽冻。
自己持有的對象真朗,一旦不再需要,持有者有義務釋放該對象僧诚,釋放時調用release方法遮婶。對象如果被釋放掉了就絕對不能被訪問。這也是為block要在堆上面的原因湖笨。
自己生成而非自己所持有對象旗扑,若用retain方法變?yōu)樽约撼钟校餐瑯涌梢杂胷elease方法釋放掉慈省。
使用autrorelease方法臀防,可以取的對象,但自己不持有對象辫呻。autorelease提供這樣的功能清钥,使對象在超出指定的生存范圍時能夠自動并正確的釋放(調用release方法)。
自己不能釋放非自己持有的對象放闺。一旦釋放會導致奔潰祟昭。
下面我們直接看代碼。
NSAllocateObject函數(shù)通過調用NSZoneMalloc函數(shù)來分配存放對象所需的內存空間怖侦,之后將該內存空間置0篡悟,最后返回作為對象而使用的指針谜叹。
對象的引用計數(shù)可以通過retainCount實例方法獲得。引用計數(shù)為0時搬葬,調用dealloc方法來銷毀對象荷腊。
引用計數(shù)表是一個散列表。
autrorelease當前超出作用域(相當于變量作用域時)急凰,對象實例的release實例方法被調用女仰。
NSAutoreleasePool對象的生存周期相當于C語言變量的作用域。對于所有調用過NSAutorelease實例方法的對象抡锈,在NSAutorepleasePool對象時疾忍,都將調用release方法。用源碼表示如下圖:
在Cocoa框架中床三,相當于程序主循環(huán)的NSRunLoop或者在其他程序可運行的地方一罩,對NSAutoreleasePool對象進行生成,持有和銷毀處理撇簿。因此應用程序開發(fā)者并不一定得使用NSAutoreleasePool對象來進行開發(fā)工作聂渊。
NSRunLoop每次循環(huán)對過程都會不斷執(zhí)行一個操作。生成NSAutoreleasePool對象四瘫,應用主程序處理銷毀NSAutoreleasePool對象汉嗽。
盡管如此,但在大量長生autorelease的對象時找蜜,只要不銷毀NSAutoreleasePool對象诊胞,那么生成的對象就不會被釋放,因此有時會產生內存不足的現(xiàn)象锹杈。比如讀入大量圖像的同時改變其尺寸。圖像文件讀入到NSData對象迈着,并從中生成UIImage對象竭望,改成尺寸后生成新的autorelease的對象。由于沒有銷毀NSAutoreleasePool對象裕菠,最終會導致內存不足咬清。
解決方法,有必要在適當?shù)牡胤缴膳耍钟谢蛘咪N毀NSAutoreleasePool對象旧烧。
通常在使用OC中,也就是Foundation框架時画髓,無論調用哪一個對象的autorelease實例方法掘剪,實現(xiàn)上是調用的都是NSObject類的aurorelease實例方法。但是對于NSAutoreleasePool類奈虾,autorelease實例方法已經被該類重載夺谁,因此運行時會報錯廉赔。
在ARC中也是遵循下面的規(guī)則的:
因此新引入4個屬性修飾符:
__strong 修飾符是id類型和對象類型默認的所有權修飾符。也就是說匾鸥,id變量蜡塌,實際上是被附加了所有權修飾符。
接下來我們看看__weak,其存在主要是為了解決相互持有造成內存泄漏的問題勿负。
接下來我們看看__unsafe_unretained修飾符:
接下來我們看看__autoreleasing修飾符
使用__week修飾的對象必定被注冊到authoreleasepool中的對象馏艾。
在iOS應用程序模版中,像下面的main函數(shù)一樣奴愉,@authoreleasepool塊包含了全部程序琅摩。
NSRunLoop等實現(xiàn)不論是否ARC,均能隨時釋放注冊到autoreleasepoo;中的對象 。
無論是否ARC,只要對象的所有者不持有該對象躁劣,該對象就被銷毀迫吐,也就是走dealloc方法。
另外账忘,在不是ARC無效時必須要調用[super dealloc]志膀。ARC的時候不必書寫這個。
另外Core Founation對象框架生成的API生成并持有的對象可以用CoreFoundation框架的API進行釋放鳖擒。