iOS MRC/ARC內(nèi)存管理基礎(chǔ)篇

1. 引用計數(shù)(Reference Count)

  • 也叫保留計數(shù)(retain count),表示對象被引用的次數(shù)。一個簡單而有效的管理對象生命周期的方式
  • C++11中的智能指針,微軟的COM,OC都是使用這個技術(shù)來實現(xiàn)內(nèi)存管理的
  • oc中,每一個對象都會有一個記錄引用次數(shù)的屬性(retainCount),可以用[object valueForKey:@"retainCount"]等方式獲取對象的引用計數(shù)

2. OC內(nèi)存管理三個進程(針對Cocoa類,CFType不包含在內(nèi))

MRC中內(nèi)存管理規(guī)則:

  • alloc ,new創(chuàng)建一個對象obj1,會自動讓對象的引用計數(shù)為1
  • 當(dāng)我們需要用一個新的指針pointer1指向上面創(chuàng)建的對象obj1的時候,除了賦值,還需要手動調(diào)用[obj1 retain]或者[obj1 copy]手動修改對象的引用計數(shù)加1
  • 在要超出指針pointer1的作用域的時候,我們需要讓手動調(diào)用[pointer1 release],讓引用計數(shù)減1

autorelease和Autoreleasepool:

Autoreleasepool理解
  • 每一個線程的 autoreleasepool 其實就是一個指針的堆棧;
  • 每一個指針代表一個需要 release 的對象或者 POOL_SENTINEL(哨兵對象,代表一個 autoreleasepool 的邊界);
  • 一個 pool token 就是這個 pool 所對應(yīng)的 POOL_SENTINEL 的內(nèi)存地址。當(dāng)這個 pool 被 pop 的時候,所有內(nèi)存地址在 pool token 之后的對象都會被 release ;
  • 這個堆棧被劃分成了一個以 page 為結(jié)點的雙向鏈表。pages 會在必要的時候動態(tài)地增加或刪除;
  • ARC下,我們使用@autoreleasepool{} 來使用一個AutoreleasePool,隨后編譯器將其改寫成下面的樣子,而這兩個函數(shù)都是對AutoreleasePoolPage的簡單封裝,所以自動釋放機制的核心就在于這個類
// {}中的代碼
void *context = objc_autoreleasePoolPush();
objc_autoreleasePoolPop(context);
  • AutoreleasePool并沒有單獨的結(jié)構(gòu),而是由若干個AutoreleasePoolPage以雙向鏈表
    的形式組合而成
  • 一個空的 AutoreleasePoolPage 的內(nèi)存結(jié)構(gòu)如下圖所示:


    image.png

magic 用來校驗 AutoreleasePoolPage 的結(jié)構(gòu)是否完整;
next 指向最新添加的 autoreleased 對象的下一個位置,初始化時指向 begin() ;
thread 指向當(dāng)前線程,所以AutoreleasePool是按線程一一對應(yīng)的
parent 指向父結(jié)點,第一個結(jié)點的 parent 值為 nil ;
child 指向子結(jié)點,最后一個結(jié)點的 child 值為 nil ;
depth 代表深度,從 0 開始,往后遞增 1;
hiwat 代表 high water mark 。
另外,當(dāng) next == begin() 時,表示 AutoreleasePoolPage 為空;當(dāng) next == end() 時,表示 AutoreleasePoolPage 已滿。

ARC下的內(nèi)存管理:

  • 底層依然是引用計數(shù)的東西,只不過編譯器幫我們在適當(dāng)?shù)奈恢锰砑覯RC中管理引用計數(shù)的代碼而已
  • 編譯器會在編譯階段以恰當(dāng)?shù)臅r間與地方給我們填上原本需要手寫的retain、release、autorelease等內(nèi)存管理代碼,所以ARC并非運行時的特性,也不是如java中的GC運行時的垃圾回收系統(tǒng);因此,我們也可以知道,ARC其實是處于編譯器的特性。
  • ARC是編譯器的特性,但也包含了運行期組件,所執(zhí)行的優(yōu)化很有意義。解釋如下:原文 鏈接
    image.png

3. CoreFoundation的內(nèi)存管理

Core Foundation 對象必須使用CFRetainCFRelease來進行內(nèi)存管理。

實際上 Core Foundation 對象使用的 CFRetain 和 CFRelease 方法,可以認(rèn)為與 Objective-C 對象的 retain 和 release 方法等價,所以我們可以以 MRC 的方式進行類似管理,有一個小習(xí)慣注意養(yǎng)成CFRelease (cfobj)之前,判斷cfobj是否為nil,不為nil時再調(diào)用release

當(dāng)使用Objective-C 和 Core Foundation 對象相互轉(zhuǎn)換的時候,怎么處理?

必須讓編譯器知道,到底由誰來負(fù)責(zé)釋放對象,是否交給ARC處理。只有正確的處理,才能避免內(nèi)存泄漏和double free導(dǎo)致程序崩潰。

__bridge:只做類型轉(zhuǎn)換,不
修改相關(guān)對象的引用計數(shù),不修改所有權(quán). 例如:原來對象是 Core Foundation ,那么對象在不用時,需要調(diào)用 CFRelease 方法。

__bridge_retained:類型轉(zhuǎn)換后,將相關(guān)對象的引用計數(shù)加1

__bridge_transfer:類型轉(zhuǎn)換后,將相關(guān)對象的引用計數(shù)交給對方權(quán)限管理

我們根據(jù)具體的業(yè)務(wù)邏輯,合理使用上面的三種轉(zhuǎn)換關(guān)鍵字,就可以解決 Core Foundation 對象與 Objective-C 對象相對轉(zhuǎn)換的問題了。

4.其他小知識點:

  • alloc ,new,copy,retain會讓引用計數(shù)器加1 , 用release,autorelease對引用計數(shù)器做減1操作
  • MRC中一定要在delloc中對對象做一次release,然后最后調(diào)用super dealloc;ARC中不需要,也不能調(diào)用super dealloc
  • ARC
  • 只支持cocoa框架下面的對象,也就是所以繼承自NSObjec的類的實例對象
  • 不支持CoreFoundation框架下面的東西,CF的內(nèi)存管理,需要手動管理,調(diào)用CFRelease(<#CFTypeRef cf#>) 和CFRetain(<#CFTypeRef cf#>)等方法管理

5.MRC下寫set,init等方法:


- (instancetype)initWithName:(NSString *)name dog:(Dog *)dog
{
    if (self = [super init]) {
        // init方法中不需要判斷_name和name是否不同,因為只會在初始化的時候調(diào)用一次
        _name = [name copy];
        _dog = [dog retain];
    }
    return self;
}

- (void)setDog:(Dog *)dog
{
    if (_dog != dog) {
        // 因為用不到舊的dog了,所以對舊的dog做一次release,
        [_dog release];
        
        // 要強引用新的dog,對新的dog做一次retain,
        _dog = [dog retain];
    }
}

- (void)setAge:(NSInteger)age
{
    _age = age; // 基本數(shù)據(jù)類型,不需要自己管理內(nèi)存
}

- (NSString *)name
{
    return _name;
}

// MRC中一定要在delloc中對對象做一次release,然后最后調(diào)用super dealloc;ARC中不需要,也不能調(diào)用super dealloc
- (void)dealloc
{
    [_dog release];
    [_name release];
    [super dealloc];

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 內(nèi)存管理 簡述OC中內(nèi)存管理機制。與retain配對使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 2,081評論 1 16
  • 為什么進行內(nèi)存管理? 由于移動設(shè)備的內(nèi)存極其有限,所以每個APP所占的內(nèi)存也是有限制的,當(dāng)app所占用的內(nèi)存較多時...
    天天想念閱讀 989評論 1 6
  • 29.理解引用計數(shù) Objective-C語言使用引用計數(shù)來管理內(nèi)存,也就是說,每個對象都有個可以遞增或遞減的計數(shù)...
    Code_Ninja閱讀 1,747評論 1 3
  • http://www.cnblogs.com/flyFreeZn/p/4264220.html 本文來源于我個人的...
    子鍵_北京不眠夜閱讀 1,032評論 0 1
  • 最近我利用碎片化時間讀了一些書,有投資理財類,有個人管理類的,也有暢銷書,共19本,我感覺現(xiàn)在和別人說自己在讀書,...
    樂活316閱讀 287評論 0 0

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