iOS 內(nèi)存管理相關(guān)總結(jié)

內(nèi)存管理是指軟件運(yùn)行時(shí)對(duì)計(jì)算機(jī)內(nèi)存資源的分配和使用的技術(shù)。其最主要的目的是如何高效,快速的分配,并且在適當(dāng)?shù)臅r(shí)候釋放和回收內(nèi)存資源。

引言

面試題:iOS內(nèi)管管理方式是什么?使用過(guò)MRC嗎?

iOS中,分有兩種內(nèi)存管理方法:

  • ARC :自動(dòng)引用計(jì)數(shù)
  • MRC :手動(dòng)引用計(jì)數(shù)

現(xiàn)在的iOS程序中,都是使用ARC了。

自動(dòng)引用計(jì)數(shù):是指內(nèi)存管理中對(duì)引用采取自動(dòng)計(jì)數(shù)的技術(shù)

那么問(wèn)題來(lái)了:

  1. 哪些對(duì)象或者內(nèi)容,可以使用此技術(shù)?
  2. 引用是什么?計(jì)數(shù)又是什么?
  3. iOS如何做到自動(dòng)引用計(jì)數(shù)的?

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

引用計(jì)數(shù)是什么?

引用計(jì)數(shù)是計(jì)算機(jī) 編程語(yǔ)言 中的一種** 技術(shù)** 內(nèi)存管理 ,是指將資源(可以是 對(duì)象 、 內(nèi)存磁盤(pán) 空間等等)的被 引用 次數(shù)保存起來(lái),當(dāng)被引用次數(shù)變?yōu)榱銜r(shí)就將其釋放的過(guò)程。使用引用計(jì)數(shù)技術(shù)可以實(shí)現(xiàn)自動(dòng)資源管理的目的。
— — 截取自百度百科

引申一個(gè)iOS 內(nèi)存分區(qū) 概念

因?yàn)?code>OC是C語(yǔ)言的超集,所以O(shè)C的內(nèi)存分區(qū)模式,可以說(shuō)直接用的是C語(yǔ)言的內(nèi)存分區(qū)模型

內(nèi)存分區(qū)圖

如上圖,內(nèi)存分區(qū)一共會(huì)分為5塊:

  • 棧區(qū)(stack)

    • 此區(qū)域存放局部變量
    • 函數(shù)跳轉(zhuǎn)地址及相關(guān)參數(shù)
    • 此區(qū)域是從高地址到低地址分配內(nèi)存的
    • 此區(qū)域內(nèi)容不需要程序員管理
  • 堆區(qū)(heap)

    • 分配我們通過(guò)alloc出的對(duì)象
    • 是從低地址到高地址分配內(nèi)存的
    • 此區(qū)域內(nèi)容必須由程序員進(jìn)行管理
  • 全局靜態(tài)區(qū)
    此區(qū)域必須要程序員管理

  • 常量區(qū)
    此區(qū)域不需要程序員管理

  • 代碼區(qū)

什么是引用計(jì)數(shù)?

通過(guò)解釋可以看出,引用計(jì)數(shù)是用于內(nèi)存管理的。解釋中,被管理的目標(biāo)是”對(duì)象”,那請(qǐng)問(wèn)對(duì)象是什么來(lái)的?

在我們的編碼過(guò)程中,需要進(jìn)行內(nèi)存管理的目標(biāo),分為兩類:
對(duì)象 與 常量
對(duì)象:即為我們通常用alloc / new出來(lái)的
對(duì)象中,又分:
是否被全局或者靜態(tài)修飾的對(duì)象
其他普通對(duì)象
常量:就是普通的內(nèi)容,基本數(shù)據(jù)類型、字符串等都有可能

對(duì)于內(nèi)存分區(qū)中的介紹中,只有在堆區(qū)的內(nèi)容,需要我們做內(nèi)存管理。而能進(jìn)入到堆區(qū)的,是對(duì)象中普通對(duì)象。

創(chuàng)建并分配堆內(nèi)存空間的對(duì)象,需要被引用并記錄的是其被引用的次數(shù)。
所以稱為”引用計(jì)數(shù)“

所以,需要使用引用計(jì)數(shù)來(lái)進(jìn)行管理的目標(biāo) 是 存放在堆區(qū)的由程序員手動(dòng)創(chuàng)建出來(lái)的

引用計(jì)數(shù)的作用

  • 當(dāng)一個(gè)對(duì)象被創(chuàng)建并在堆內(nèi)分配內(nèi)存后,對(duì)象自身將會(huì)有一個(gè)屬性-引用計(jì)數(shù),此時(shí)引用計(jì)數(shù)為1
  • 當(dāng)有其他對(duì)象需要持有該對(duì)象時(shí),引用計(jì)數(shù)+1
  • 當(dāng)有其他對(duì)象需要釋放(放棄持有)該對(duì)象時(shí),引用計(jì)數(shù)-1
  • 當(dāng)該對(duì)象的引用計(jì)數(shù)為0時(shí),系統(tǒng)將會(huì)銷毀對(duì)象并回收其內(nèi)存地址

由此可見(jiàn),系統(tǒng)通過(guò)對(duì)象的引用計(jì)數(shù),控制著對(duì)象的生命周期,從而實(shí)現(xiàn)內(nèi)存空間資源管理的目的

一個(gè)小補(bǔ)充:

本文并不打算做代碼層面的測(cè)試,雖然,我們可以通過(guò)對(duì)對(duì)象[object retainCount]的方法來(lái)打印對(duì)象的引用計(jì)數(shù)
但是,在某些測(cè)試場(chǎng)景中,打印出的引用計(jì)數(shù)會(huì)是一個(gè)無(wú)限大的數(shù),此為系統(tǒng)內(nèi)部做了處理,且ARC下不建議直接使用retainCount方法,所以本文暫不做研究。有興趣的,可以自己通過(guò)打印,看看數(shù)是多少(絕大多數(shù)情況下retainCount的數(shù)值還是正確的)~

iOS中有關(guān)引用計(jì)數(shù)的內(nèi)存管理方法

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

  • 自己生成的對(duì)象,自己所持有
id obj = [[NSObject alloc] init];
  • 非自己生成的對(duì)象,自己也能持有
id obj = [NSMutableArray array];
  • 不再需要自己持有的對(duì)象時(shí)釋放
[obj release];
或者
[obj autorelease];
  • 非自己持有的對(duì)象無(wú)法釋放

了解有哪些方法,會(huì)對(duì)對(duì)象引用計(jì)數(shù)造成變更

  • 生成并持有對(duì)象:alloc/new/copy/mutablecopy
    如此 引用計(jì)數(shù)+1
  • 持有對(duì)象 :retain
    如此 引用計(jì)數(shù)+1
  • 釋放對(duì)象 :release/autorelease
    如此 引用計(jì)數(shù) -1
  • 回收對(duì)象 :dealloc
    如此 將沒(méi)有引用計(jì)數(shù)

前面引言中已經(jīng)說(shuō)了,iOS中,基于引用計(jì)數(shù)可以引申出兩種內(nèi)存管理方式:

  1. ARC
  2. MRC

MRC手動(dòng)引用計(jì)數(shù)

即對(duì)象的引用計(jì)數(shù)管理,交由程序員手動(dòng)處理,操作系統(tǒng)(iOS)不做任何干預(yù),只在對(duì)象引用計(jì)數(shù)為0時(shí),將對(duì)象在合適時(shí)機(jī)銷毀。

自行添加各種對(duì)引用計(jì)數(shù)操作的代碼,這樣,代碼量將會(huì)增加,并一不小心,就會(huì)出現(xiàn)內(nèi)存泄漏的問(wèn)題

所以,在ARC出現(xiàn)后,基本上已經(jīng)放棄了MRC的操作了,只要一些可能的老舊第三方庫(kù)還在使用吧。(這個(gè),也應(yīng)該基本沒(méi)有了,當(dāng)然不排除還有些在用MRC的)

ARC自動(dòng)引用計(jì)數(shù)

本質(zhì)部分在引用計(jì)數(shù)式內(nèi)存管理層面,ARC并沒(méi)有改變,也是使用引用計(jì)數(shù)來(lái)管理對(duì)象。只是ARC自動(dòng)的幫助我們處理”引用計(jì)數(shù)“相關(guān)部分

ARC獨(dú)有內(nèi)存管理思考方式

首先聲明一點(diǎn):iOS內(nèi)存管理思考方式思考方式就是因?yàn)锳RC的引用所帶來(lái)的變化而且思考出的一個(gè)結(jié)論,此結(jié)論對(duì)ARC和MRC均有效,但ARC多了一個(gè)所有權(quán)聲明

ARC — 所有權(quán)修飾符

簡(jiǎn)單的說(shuō),就是ARC下,使用所有權(quán)修飾符,告訴編譯器對(duì)此對(duì)象做何種內(nèi)存相關(guān)操作。

所有權(quán)修飾符有4鐘:

  • ?__strong
  • __weak
  • __unsafe_unretained
  • __autoreleasing

__strong

是所有id類型和對(duì)象的默認(rèn)所有權(quán)修飾符
作用:強(qiáng)持有此對(duì)象,在對(duì)象超出其作用域時(shí),強(qiáng)引用失效,釋放此對(duì)象

代碼演示:

--- ARC ---
{
    id obj = [NSObject new];
}

--- MRC ---
{
    id obj = [NSObject new];
    [obj release];
}

上面兩段代碼等價(jià)!即出了作用域了,將obj釋放
__strong不僅可以作用在局部變量上,也可以作用在成員變量、屬性上。作用一致,只是需要釋放的位置,可能不同。成員變量和屬性,需要在對(duì)象被釋放前釋放掉

__weak

__strong所有權(quán),將對(duì)象強(qiáng)持有,如果釋放不當(dāng)或者使用不當(dāng),將會(huì)造成APP一個(gè)名場(chǎng)面 :****循環(huán)引用****

所以__weak的作用:提供弱引用,不能持有對(duì)象實(shí)例,即不會(huì)造成對(duì)象引用計(jì)數(shù)的改變
因?yàn)槭褂昧?code>__weak不持有對(duì)象,當(dāng)對(duì)象超出作用域后,會(huì)被立即釋放

循環(huán)引用是因?yàn)橛袃蓚€(gè)對(duì)象相互強(qiáng)引用導(dǎo)致,用__weak打破兩者間相互強(qiáng)引用的關(guān)系,即可解決循環(huán)引用的問(wèn)題。

__unsafe_unretained和__autoreleasing

一個(gè)是不安全不引用修飾符,一個(gè)是自動(dòng)釋放修飾符
前者因?yàn)槠涫褂脮?huì)造成程序出現(xiàn)不確定的異常,所以基本不用
后者因?yàn)樵贏RC下,無(wú)法使用autorelease方法,所以也是基本不使用

所有權(quán)修飾符和屬性的修飾符對(duì)應(yīng)關(guān)系如下所示:

  • assign 對(duì)應(yīng)的所有權(quán)類型是 __unsafe_unretained
  • copy 對(duì)應(yīng)的所有權(quán)類型是 __strong
  • retain 對(duì)應(yīng)的所有權(quán)類型是 __strong
  • strong 對(duì)應(yīng)的所有權(quán)類型是 __strong
  • unsafe_unretained對(duì)應(yīng)的所有權(quán)類型是__unsafe_unretained
  • weak 對(duì)應(yīng)的所有權(quán)類型是 __weak

ARC有效使用規(guī)則

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

ARC不適用場(chǎng)景 —— Core Foundation對(duì)象

ARC對(duì)C語(yǔ)言編寫(xiě)的Core Foundation框架中對(duì)象無(wú)效,所以,使用了該框架中的對(duì)象,需要使用其對(duì)應(yīng)的引用計(jì)數(shù)方法CFRetain/CFRealease

Foundation框架與Core Foundation框架對(duì)象的區(qū)別,只是在哪個(gè)框架下生成而已,生成之后,可以在不同框架下使用。


4C717DC7-8321-48E6-B84D-A0B70C9313A2.png
最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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