iOS內(nèi)存管理

一.內(nèi)存管理 /引用計(jì)數(shù)

Objective-C 中的內(nèi)存管理遵绰,也就是引用計(jì)數(shù)

1.1內(nèi)存管理的思考方式

  • 自己生成的對(duì)象沸伏,自己持有
  • 非自己生成的對(duì)象莫湘,自己也能持有
  • 不再需要自己持有的對(duì)象時(shí)釋放
  • 非自己持有的對(duì)象無(wú)法釋放
    注意: "自己"是指"對(duì)象的使用環(huán)境"变逃,以上內(nèi)存管理思考方式在MRC與ARC下都是可行的贝搁,只是源代碼的記述方法稍有不同吗氏,可以從后文中所述ARC中追加的所有權(quán)聲明開(kāi)始理解。
演示文稿.001.jpeg

在objective-c內(nèi)存管理中雷逆,"生成"弦讽,"持有","釋放"和"廢棄"四個(gè)詞頻繁出現(xiàn)膀哲,這些內(nèi)存管理方法不包括在該語(yǔ)言中往产,而是由Cocoa框架中Foundation框架類庫(kù)的NSObject類擔(dān)負(fù)內(nèi)存管理的職責(zé)

框架與類的關(guān)系.jpeg

1.1.1 自己生成的對(duì)象,自己持有

使用以下名稱開(kāi)頭的方法意味著自己生成的對(duì)象只有自己持有

  • alloc
  • new
  • copy
  • mutableCopy
    此外某宪,使用駝峰寫法(CamelCase)命名的下列名稱也意味著自己生成并持有對(duì)象
  • allocMyObject
  • newThatObject
  • copyThis
  • mutableCopyYourObject

1.1.2 非自己生成的對(duì)象仿村,自己也能持有

用上述之外方法取得的對(duì)象,因?yàn)榉亲约荷刹⒊钟行宋梗宰约翰皇窃搶?duì)象的持有者蔼囊,如NSMutableArray類的 array類方法。
通過(guò)使用retain方法衣迷,非自己生成的對(duì)象跟用第一類方法生成并持有的對(duì)象一樣畏鼓,成為了自己所持有的。

1.1.3 不再需要自己持有的對(duì)象時(shí)釋放

自己持有的對(duì)象壶谒,一旦不再需要云矫,持有者有義務(wù)釋放該對(duì)象,釋放使用release方法汗菜。

  • 用alloc方法由自己生成并持有的對(duì)象通過(guò)release方法釋放

  • 自己生成而非自己持有的對(duì)象让禀,若用retain方法變?yōu)樽约撼钟校瑯涌梢杂胷elease方法釋放

  • 用某個(gè)方法生成對(duì)象陨界,并將其返還給該方法的調(diào)用方巡揍,這種情況下:

    • 原封不動(dòng)地返回alloc方法生成并持有的對(duì)象,就能讓調(diào)用方也持有該對(duì)象(被調(diào)用方法名符合alloc等方法命名規(guī)則)

      - (id)allocObject {
      //自己生成并持有對(duì)象
      id obj =[ [NSObject alloc] init];
      //自己持有對(duì)象
      return obj普碎;
      }
      // 取得非自己生成并持有的對(duì)象
      id obj1 = [ obj0 allocObject];
      自己持有對(duì)象
      
  • 調(diào)用 [NSMutableArray array]方法取得的對(duì)象存在吼肥,但自己不持有對(duì)象录平,又是如何實(shí)現(xiàn)的呢
    - (id)object {
    id obj = [[NSObject alloc] init];
    //自己持有對(duì)象
    [obj autorelease];
    //取得的對(duì)象存在麻车,但自己不持有對(duì)象
    return obj缀皱;
    }
    id obj1 = [obj0 object];
    //取得的對(duì)象存在,但自己不持有對(duì)象动猬,當(dāng)然也能夠通過(guò)retain方法調(diào)用autorelease方法取得的對(duì)象變?yōu)樽约撼钟衅《罚缦?br> [obj1 retain];
    //自己持有對(duì)象
    autorelease提供這樣的功能,使對(duì)象在超出指定的生存范圍時(shí)能夠自動(dòng)并正確的釋放

1.1.4 無(wú)法釋放非自己持有的對(duì)象

  • 自己生成并持有對(duì)象后赁咙,在釋放完不再需要的對(duì)象之后再次釋放
  • 取得的對(duì)象存在钮莲,但自己不持有對(duì)象時(shí)釋放

1.2 autorelease

看上去很像ARC,實(shí)際上更類似C語(yǔ)言中自動(dòng)變量(局部變量)的特性:

{
    int a;
}
 //因?yàn)槌鲎兞孔饔糜虮怂詣?dòng)變量"int a"被廢棄崔拥,不可再訪問(wèn)

autorelease會(huì)像c語(yǔ)言自動(dòng)變量這樣來(lái)對(duì)待對(duì)象實(shí)例凤覆。當(dāng)超出其作用域時(shí),對(duì)象實(shí)例的release實(shí)例方法被調(diào)用盯桦。不同的是,可以設(shè)定變量的作用域拥峦。

autorelease具體使用方法如下:
  • 生成并持有NSAutoreleasePool對(duì)象贴膘;
  • 調(diào)用已分配對(duì)象的autorelease實(shí)例方法;
  • 廢棄NSAutoreleasePool對(duì)象刑峡。

NSAutoreleasePool對(duì)象的生命周期相當(dāng)于c語(yǔ)言變量的作用域玄柠。對(duì)于所有調(diào)用過(guò)autorelease實(shí)例方法的對(duì)象氛琢,在廢棄NSAutoreleasePool對(duì)象時(shí),都將調(diào)用release實(shí)例方法随闪。

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];   //等同于[obj release];

在Cocoa框架中阳似,相當(dāng)于程序主循環(huán)的NSRunLoop或者在其他程序可運(yùn)行的地方铐伴,對(duì)NSAutoreleasePool對(duì)象進(jìn)行生成、持有和廢棄處理畜吊。所以應(yīng)用程序開(kāi)發(fā)者不一定非得使用NSAutoreleasePool對(duì)象來(lái)進(jìn)行開(kāi)發(fā)工作户矢。


NSRunLoop每次循環(huán)過(guò)程中NSAutoreleasePool對(duì)象被生成貨廢棄.jpeg

盡管如此,在大量產(chǎn)生autorelease對(duì)象時(shí),只要不廢棄NSAutoreleasePool對(duì)象捌年,那么生成的對(duì)象就不能被釋放,因此有時(shí)會(huì)產(chǎn)生內(nèi)存不足的現(xiàn)象眠砾。典型的例子時(shí)讀入大量圖像的同時(shí)改變其尺寸托酸。圖像文件讀入到NSData對(duì)象,并從中生成UIImage對(duì)象励堡,改變?cè)搶?duì)象尺寸后生成新的UIImage對(duì)象,這種情況下會(huì)大量產(chǎn)生autorelease對(duì)象淤井。

for(int i = 0; i<圖像數(shù)摊趾;++i) {
    /*
     *讀入圖像
     *大量產(chǎn)生autorelease的對(duì)象
     *由于沒(méi)有廢棄NSAutoreleasePool對(duì)象
     *最終導(dǎo)致內(nèi)存不足
    */
}

在此情況下,有必要在適當(dāng)?shù)牡胤缴衫恪⒊钟谢驈U棄NSAutoreleasePool對(duì)象。

for(int i = 0; i<圖像數(shù)止吐;++i) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 /*
  *讀入圖像
  *大量產(chǎn)生autorelease的對(duì)象
  */
  [pool drain];
 /*
  *通過(guò)[pool drain],
  *autorelease  
  */
}

二. ARC規(guī)則

實(shí)際上"引用計(jì)數(shù)式內(nèi)存管理"的本質(zhì)部分在ARC中并沒(méi)有改變侨糟,ARC只是自動(dòng)地幫助我們處理"引用計(jì)數(shù)"的相關(guān)部分。

2.1所有權(quán)修飾符

ARC有效時(shí)秕重,id類型和對(duì)象類型同c語(yǔ)言其他類型不同,其類型上必須附加所有權(quán)修飾符二拐。所有權(quán)修飾符一共有4種凳兵。

  • __strong修飾符
  • __weak修飾符
  • __unsafe_unretained修飾符
  • __autoreleasing修飾符

2.1.1 __strong修飾符

_ _strong修飾符是id類型和對(duì)象類型默認(rèn)的所有權(quán)修飾符。在沒(méi)有明確指定所有權(quán)修飾符時(shí)庐扫,id和對(duì)象類型默認(rèn)為_(kāi)_strong修飾符仗哨。

以下兩種代碼表意相同
id obj = [[NSObject alloc] init];
id __strong obj = [[NSObject alloc] init];

如"strong"名稱所示铅辞,附有 _ _strong修飾符表示對(duì)對(duì)象的"強(qiáng)引用",附有 __strong修飾符的變量obj在超出其變量作用域時(shí)巷挥,即在該變量被廢棄時(shí)验靡,會(huì)釋放其被賦予的對(duì)象,如下:

1. 自己生成并持有對(duì)象
{
    //自己生成并持有對(duì)象
    id __strong obj = [[NSObject alloc] init];
    //因?yàn)樽兞縪bj為強(qiáng)引用高职,所以自己持有對(duì)象
}
    //因?yàn)樽兞縪bj超出其作用域辞州,強(qiáng)引用失效
    //所以自動(dòng)地釋放自己持有的對(duì)象。
    //對(duì)象的所有者不存在变过,因此廢棄該對(duì)象

2.取得非自己生成并持有的對(duì)象
{
    //取得非自己生成并持有的對(duì)象
    id __strong obj = [NSMutableArray array];
    //因?yàn)樽兞縪bj為強(qiáng)引用,所以自己持有對(duì)象   
}
    //因?yàn)樽兞縪bj超出其作用域媚狰,強(qiáng)引用實(shí)效,
    //所以自動(dòng)地釋放自己持有的對(duì)象

附有__strong修飾符的變量之間可以相互賦值沧踏。
舉例暫略
即便是objective-c類成員變量,也可以在方法參數(shù)上遗锣,使用附有 _strong修飾符的變量
舉例暫略
另外嗤形,__strong修飾符通后面要講的__weak修飾符合__autorelease修飾符一起,可以保證獎(jiǎng)附有這些修飾符的自動(dòng)變量初始化為nil赋兵。

2.1.2 __weak修飾符

僅通過(guò)__strong修飾符是不能解決有些重大問(wèn)題的,帶有__strong修飾符的成員變量在持有對(duì)象時(shí)拓轻,很容易發(fā)生循環(huán)引用经伙。循環(huán)引用容易發(fā)生內(nèi)存泄漏勿锅。所謂內(nèi)存泄漏就是應(yīng)當(dāng)廢棄的對(duì)象在超出其生存期后繼續(xù)存在枣氧。
使用__weak修飾符可以避免循環(huán)引用溢十。__weak修飾符與__strong修飾符相反达吞,提供弱引用。弱引用不能持有對(duì)象實(shí)例吞鸭,所以在超出其變量作用域時(shí)覆糟,對(duì)象即被釋放。
舉例待補(bǔ)滩字。。麦箍。
__weak修飾符還有另一有點(diǎn)挟裂,在持有某對(duì)象的弱引用時(shí),若該對(duì)象被廢棄话瞧,則此弱引用將自動(dòng)失效且處于nil被賦值的狀態(tài),通過(guò)檢查附有__weak修飾符的變量是否為nil划滋,可以判斷被賦值的對(duì)象是否已廢棄埃篓。

2.1.3__unsafe_unretained修飾符

__unsafe_unretained修飾符正如其名unsafe所示,是不安全的所有權(quán)修飾符架专。盡管ARC式的內(nèi)存管理是編譯器的工作,但附有__unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對(duì)象想邦。
附有__unsafe_unretained修飾符的變量同附有_weak修飾符的變量一樣委刘,因?yàn)樽约荷刹⒊钟械膶?duì)象不能繼續(xù)為自己所有鹰椒,所以生成的對(duì)象會(huì)立即被釋放呕童。
舉例很重要,待補(bǔ)充奸汇。往声。。
在使用__unsafe_unretained修飾符時(shí)烁挟,賦值給附有__strong 修飾符的變量時(shí)有必要確保被賦值的對(duì)象卻是存在骨坑。使用__unsafe_unretained修飾符變量的必要性:在iOS4的應(yīng)用程序中,必須使用__unsafe_unretained修飾符來(lái)替代__weak修飾符且警。賦值給附有__unsafe_unretained修飾符變量的對(duì)象在通過(guò)該變量使用時(shí)礁遣,如果沒(méi)有確保其確實(shí)存在,那么應(yīng)用程序就會(huì)崩潰杏头。

2.1.4__autorealeasing修飾符

ARC有效時(shí)

  • 不能使用autorelease方法

  • 不能使用NSAutoreleasePool類
    這樣以來(lái)沸呐,雖然autorelease無(wú)法直接使用,但ARC有效時(shí)autorelease功能是起作用的崭添。

    //ARC無(wú)效
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [[NSObject alloc] init];
    [obj autorelease];
    [pool drain];
    
     //ARC有效時(shí),該源碼能寫成下面這樣:
     @autoreleasepool {
            id __autoreleasing obj = [[NSObject alloc] init];
     }
    

指定"@ autoreleasepool塊"來(lái)替代"NSAutoreleasePool"類對(duì)象生成棘伴、持有即廢棄"這一范圍屁置,但是,顯式地附加__autoreleasing修飾符同顯式地附加__strong修飾符一樣罕見(jiàn)淳地,autoreleasing不同于autorelease,它用于按引用傳遞對(duì)象
@ autoreleasepool圖片表述待補(bǔ)
@ autoreleasepool四個(gè)非顯式使用_autoreleasing修飾符的例子

2.2規(guī)則

  • 不能使用retain/release/retainCount/autorelease
  • 不能使用NSAllocateObject/NSDeallocateObject
  • 須遵守內(nèi)存管理的方法命名規(guī)則
  • 不要顯式調(diào)用dealloc
  • 使用@autoreleasepool塊替代NSAutoreleasePool
  • 不能使用區(qū)域(NSZone)
  • 對(duì)象型變量不能作為c語(yǔ)言結(jié)構(gòu)體(struct/union)的成員
  • 顯式轉(zhuǎn)換"id"和"void*"
2.2.1 不能使用retain/release/retainCount/autorelease
2.2.2 不能使用NSAllocateObject/NSDeallocateObject
2.2.3 須遵守內(nèi)存管理的方法命名規(guī)則

在ARC無(wú)效時(shí)伍伤,用于對(duì)象生成/持有的方法必須遵守以下命名規(guī)則
alloc/new/copy/mutableCopy遣钳,上述名稱開(kāi)始的方法在返回對(duì)象時(shí),必須返回給調(diào)用房所應(yīng)當(dāng)持有的對(duì)象蕴茴。這在ARC有效時(shí)也一樣,返回的對(duì)象完全沒(méi)有改變蒋畜。只是在ARC有效時(shí)要追加一條命名規(guī)則撞叽。

  • init
    以init開(kāi)始的方法的規(guī)則要比alloc/new/copy/mutableCopy更嚴(yán)格。該方法必須時(shí)實(shí)例方法科展,并且必須要返回對(duì)象糠雨。返回的對(duì)象應(yīng)為id類型或該方法聲明類的對(duì)象類型,抑或是該類的超類型或子類型甘邀。該返回對(duì)象并不注冊(cè)到autoreleasepool上∥肭伲基本上只是對(duì)alloc方法返回值的對(duì)象進(jìn)行初始化處理病返回該對(duì)象测摔。
    以init開(kāi)始的方法的命名規(guī)則:

    • (id)initWithObject:(id)obj; //可以
    • (void)initThisObject; //遵守了命名規(guī)則,但雖然以init開(kāi)始锋八,卻沒(méi)有返回對(duì)象挟纱,不能使用
    • (void)initialize; //不包含在命名規(guī)則里
2.2.4 不要顯式調(diào)用dealloc

對(duì)象被廢棄時(shí),不管ARC是否有效紊服,都會(huì)調(diào)用對(duì)象的dealloc方法
dealloc方法在大多數(shù)情況下還適用于刪除已注冊(cè)的代理或觀察者對(duì)象

2.2.5 使用@autoreleasepool塊替代NSAutoreleasePool
2.2.6不能使用區(qū)域(NSZone)
2.2.7對(duì)象型變量不能作為c語(yǔ)言結(jié)構(gòu)體(struct/union)的成員
2.2.8顯式轉(zhuǎn)換"id"和"void*"

2.3 屬性

屬性時(shí)在Objective-c2.0引入的,提供了一種輕松地為類聲明實(shí)例變量的方式参萄,并讓編譯器自動(dòng)生成存取方法。
當(dāng)ARC有效時(shí)校赤,以下可作為這種屬性聲明中使用的屬性來(lái)用

屬性聲明的屬性與所有權(quán)修飾符的對(duì)應(yīng)關(guān)系.jpeg

2.4數(shù)組

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末筒溃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子浑测,更是在濱河造成了極大的恐慌歪玲,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漱贱,死亡現(xiàn)場(chǎng)離奇詭異夭委,居然都是意外死亡募强,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門慌烧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鸠儿,“玉大人,你說(shuō)我怎么就攤上這事进每。” “怎么了嘱兼?”我有些...
    開(kāi)封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵贤徒,是天一觀的道長(zhǎng)汇四。 經(jīng)常有香客問(wèn)我踢涌,道長(zhǎng),這世上最難降的妖魔是什么利虫? 我笑而不...
    開(kāi)封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任堡僻,我火速辦了婚禮,結(jié)果婚禮上硼讽,老公的妹妹穿的比我還像新娘牲阁。我一直安慰自己,他們只是感情好城菊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布凌唬。 她就那樣靜靜地躺著,像睡著了一般客税。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上测垛,一...
    開(kāi)封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天秧均,我揣著相機(jī)與錄音,去河邊找鬼锯七。 笑死讶隐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播地消,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼畏妖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了半夷?” 一聲冷哼從身側(cè)響起迅细,我...
    開(kāi)封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎湘换,沒(méi)想到半個(gè)月后统阿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡帆离,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年结澄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片概而。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赎瑰,死狀恐怖破镰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鲜漩,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布踩娘,位于F島的核電站喉祭,受9級(jí)特大地震影響雷绢,放射性物質(zhì)發(fā)生泄漏理卑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一帆疟、第九天 我趴在偏房一處隱蔽的房頂上張望宇立。 院中可真熱鬧,春花似錦妈嘹、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至尔苦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間魂那,已是汗流浹背稠项。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留活逆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓蔗候,卻偏偏與公主長(zhǎng)得像埂软,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子所灸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 貌似每個(gè)iOS開(kāi)發(fā)者都有一篇屬于自己的內(nèi)存管理,記錄了自己對(duì)內(nèi)存管理理解的深度以及廣度蚊夫,所以我也來(lái)記錄一下我的理解...
    Bugfix閱讀 2,263評(píng)論 0 3
  • ARC在編譯期間懦尝,根據(jù)Objective-C對(duì)象的存活周期,在適當(dāng)?shù)奈恢锰砑觬etain和release代碼琅轧。從概...
    朽木自雕也閱讀 1,046評(píng)論 0 1
  • 終于明白那些年知其然而不知其所以然的iOS內(nèi)存管理方式 前言 從我開(kāi)始學(xué)習(xí)iOS的時(shí)候踊挠,身邊的朋友、網(wǎng)上的博客都告...
    楓宇翔閱讀 7,332評(píng)論 8 49
  • 2017年的情人節(jié)剛剛過(guò)去睹酌,看著一對(duì)對(duì)幸福的情人剩檀,與戀人憋沿,不由得想起了初戀。 都說(shuō)辐啄,初戀是人間最美的感情运嗜,讓多少人...
    云淑閱讀 228評(píng)論 1 2
  • 花了好幾個(gè)小時(shí)看完了這本書《超級(jí)聊天術(shù)》,基本都是利用晚上睡覺(jué)前看的砸民,內(nèi)容非常通俗易懂。 首先通過(guò)列舉閑聊的五大原...
    感受背影閱讀 268評(píng)論 0 0