iOS內(nèi)存管理
內(nèi)存區(qū)域劃分
| 內(nèi)存區(qū)域 | 說明 |
|---|---|
| 棧區(qū) | 存放局部變量,系統(tǒng)自動(dòng)分配和釋放。 特點(diǎn):容量小,速度快,有序 |
| 堆區(qū) | 存放new或malloc操作的內(nèi)存,比如對(duì)象。一般由程序員分配和釋放,可能會(huì)出現(xiàn)內(nèi)存泄露和循環(huán)引用的問題。 特點(diǎn): 容量大,速度慢,無序 |
| 靜態(tài)區(qū) | 存放全局變量和靜態(tài)變量。程序結(jié)束時(shí),系統(tǒng)回收 |
| 常量區(qū) | 存放常量。程序結(jié)束時(shí),系統(tǒng)回收 |
| 代碼區(qū) | 存放二進(jìn)制代碼區(qū)域 |
從上述分類上看,我們?cè)陂_發(fā)過程中主要涉及的是堆上內(nèi)存的管理。
引用計(jì)數(shù)
Objective-C 和 Swift 的 iOS 運(yùn)行時(shí)使用引用計(jì)數(shù)。使用引用計(jì)數(shù)的負(fù)面影響在于,如果開發(fā)人員不夠小心,那么可能會(huì)出現(xiàn)重復(fù)的內(nèi)存釋放和循環(huán)引用的情況。
引用計(jì)數(shù)管理對(duì)象生命周期如下:

Objective-C
// 創(chuàng)建對(duì)象
BaseModel *model = [BaseModel new];
// 持有對(duì)象
id model1 = model;
Swift
// 創(chuàng)建對(duì)象
var model = BaseModel()
// 持有對(duì)象
var model1: Any = model
taggedPointer
從64位開始,iOS引入了Tagged Pointer技術(shù),用于優(yōu)化NSNumber、NSDate、NSString等小對(duì)象的存儲(chǔ)。
在沒有使用Tagged Pointer之前, NSNumber等對(duì)象需要?jiǎng)討B(tài)分配內(nèi)存、維護(hù)引用計(jì)數(shù)等,NSNumber指針存儲(chǔ)的是堆中NSNumber對(duì)象的地址值。
使用Tagged Pointer之后,NSNumber指針里面存儲(chǔ)的數(shù)據(jù)變成了:Tag + Data(標(biāo)記類型+數(shù)據(jù)),也就是將數(shù)據(jù)直接存儲(chǔ)在了指針中,當(dāng)指針(8字節(jié))不夠存儲(chǔ)數(shù)據(jù)時(shí),才會(huì)使用動(dòng)態(tài)分配內(nèi)存的方式來存儲(chǔ)數(shù)據(jù)。
PS: Swift中經(jīng)常使用的是值類型,比如Int,String,struct等。所以對(duì)指針的依賴比較少。
SideTables
SideTables由多個(gè)SideTable組成,SideTables本質(zhì)是一個(gè)哈希表。SideTables的hash key為對(duì)象的地址。所以一個(gè)對(duì)象對(duì)應(yīng)一個(gè)SideTable,一個(gè)SideTable又包含多個(gè)對(duì)象。
SideTable主要存放了對(duì)象的引用計(jì)數(shù)和弱引用相關(guān)信息。弱引用對(duì)象會(huì)先保存在SideTables。弱引用對(duì)象如果長期沒有被清理掉的話會(huì)成為僵尸對(duì)象。這樣可以僵尸對(duì)象長期占用內(nèi)存情況下,不再需要保存僵尸對(duì)象,只保存引用計(jì)數(shù)和原對(duì)象指針內(nèi)存占據(jù)非常小的SideTables。
SideTable中包含三個(gè)成員,自旋鎖,引用計(jì)數(shù)表,弱引用表。
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table;
- slock是一個(gè)自旋鎖,就是為了保證多線程訪問安全性。如果當(dāng)前鎖已被其他線程獲取,那么當(dāng)前線程會(huì)不斷的探測(cè)鎖是否被釋放,如果釋放,自己第一時(shí)間獲取這個(gè)鎖
- refcnts本質(zhì)是一個(gè)存儲(chǔ)對(duì)象引用計(jì)數(shù)的hash表,key為對(duì)象,value為引用計(jì)數(shù)(優(yōu)化過得isa中,引用計(jì)數(shù)主要存儲(chǔ)在isa中)
- weak_table是存儲(chǔ)對(duì)象弱引用的一個(gè)結(jié)構(gòu)體
SideTables結(jié)構(gòu)圖如下:

ARC 和 MRC
MRC是需要調(diào)用對(duì)應(yīng)的方法來管理引用計(jì)數(shù)。
ARC是自動(dòng)管理引用計(jì)數(shù)。
PS:
(1)Objective-C是支持MRC和ARC,Swift是不支持MRC,只支持ARC的。
(2)ARC是通過LLVM和Runtime協(xié)作的,ARC禁止手動(dòng)調(diào)用
retain/release
(3)Objective-C只是 Cocoa API中支持了ARC。Objective-C 中的其他常用 API,例如 Core Graphics,不支持 ARC。
| MRC | ARC | |
|---|---|---|
| strong | 無 | ARC特有,MRC沒有,相當(dāng)于MRC模式的retain |
| retain | 手動(dòng)創(chuàng)建 | 自動(dòng)創(chuàng)建 |
| assgin | 可以用來修飾對(duì)象類型,也可以用來修飾基本數(shù)據(jù)類型。修飾對(duì)象類型的時(shí)候,對(duì)象的引用計(jì)數(shù)不會(huì)隨著引用次數(shù)的增加而增加,也就是說被釋放之前,引用計(jì)數(shù)永遠(yuǎn)是1 | 只能用來修飾基本數(shù)據(jù)類型,不能用來修飾對(duì)象類型。除此之外,還用來修飾代理對(duì)象。 |
| weak | 無 | ARC特有,MRC沒有,相當(dāng)于MRC模式的assgin |