iOS內(nèi)存管理

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ì)象生命周期如下:

image.png

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)圖如下:


image.png

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
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 目錄一、iOS的內(nèi)存管理方式? 1、小對(duì)象的內(nèi)存管理 -- Tagged Pointer?? 1.1 Tagged...
    意一ineyee閱讀 2,842評(píng)論 3 39
  • 1、內(nèi)存布局 stack:方法調(diào)用 heap:通過alloc等分配對(duì)象 bss:未初始化的全局變量等。 data:...
    AKyS佐毅閱讀 1,722評(píng)論 0 19
  • iOS程序的內(nèi)存布局 Tagged Pointer 從64bit開始,iOS引入了Tagged Pointer技術(shù)...
    陳盼同學(xué)閱讀 557評(píng)論 0 4
  • 一、在 Obj-C 中,如何檢測(cè)內(nèi)存泄漏?你知道哪些方式? 目前我知道的方式有以下幾種 Memory Leaks ...
    maskerII閱讀 477評(píng)論 0 0
  • 內(nèi)存管理1 var 內(nèi)存兩大區(qū) = {內(nèi)核區(qū),用戶區(qū)} 1.內(nèi)存布局 內(nèi)存的布局是內(nèi)存六大區(qū):棧區(qū),堆區(qū),全局/靜...
    f8d1cf28626a閱讀 378評(píng)論 0 3

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