iOS內(nèi)存管理中引用計(jì)數(shù)的學(xué)習(xí)
1.引用計(jì)數(shù)的思考方式
- 自己生成的對(duì)象,自己持有
- 非自己生成的對(duì)象,自己也能持有
- 不在需要自己持有的對(duì)象時(shí)釋放
- 非自己持有的對(duì)象無(wú)法釋放
2.引用計(jì)數(shù)的實(shí)現(xiàn)
1.alloc方法
+ alloc + allocWithZone: class_creatInstance calloc
調(diào)用alloc方法首先調(diào)用allocWithZone:類方法,然后調(diào)用class_creatInstance函數(shù),最后調(diào)用calloc來(lái)分配內(nèi)存塊。
2.ratainCount/retain/release 方法
- retainCount __CFDoExternRefOperation CFBasicHashGetCountOfKey
- retain __CFDoExternRefOperation CFBasicHashAddValue
-retainCount __CFDoExternRefOperation CFBasicHashRemoveValue //CFBasicHashRemoveValue 為0時(shí),-release調(diào)用dealloc
各個(gè)方法都通過(guò)同一個(gè)__CFDoExternRefOperation函數(shù),調(diào)用一系列名稱相似的函數(shù)。并且從函數(shù)名看出蘋果采用散列表(引用計(jì)數(shù)表)來(lái)管理引用計(jì)數(shù),表鍵值為內(nèi)存塊地址的散列值。然而GNUStep將引用計(jì)數(shù)保存在對(duì)象占用內(nèi)存塊頭部的變量中(objc_layout這個(gè)結(jié)構(gòu)體中)。
內(nèi)存塊頭部管理引用計(jì)數(shù)的好處:
- 少量代碼皆可完成
- 能夠統(tǒng)一管理引用計(jì)數(shù)內(nèi)存塊與對(duì)象內(nèi)存塊。
引用技術(shù)表管理引用計(jì)數(shù)的好處:
1. 對(duì)象內(nèi)存快的分配無(wú)需考慮內(nèi)存塊頭部
引用計(jì)數(shù)表各記錄中存有內(nèi)存塊地址,可從各個(gè)記錄追溯到各個(gè)內(nèi)存塊。
第二條特征在調(diào)試時(shí)很重要,即使出現(xiàn)故障導(dǎo)致對(duì)象占用的內(nèi)存塊損壞,但只要引用計(jì)數(shù)表沒(méi)有被損壞,就能夠確認(rèn)各個(gè)內(nèi)存塊的地址
3.autorelease方法
NSAutoreleasePool是通過(guò)以AutoreleasePoolPage為結(jié)點(diǎn)的雙向鏈表來(lái)實(shí)現(xiàn)的。AutoreleasePoolPage是一個(gè)C++實(shí)現(xiàn)的類,類結(jié)構(gòu)如圖:

- magic 用來(lái)校驗(yàn) AutoreleasePoolPage 的結(jié)構(gòu)是否完整;
- next 指向最新添加的 autoreleased 對(duì)象的下一個(gè)位置,初始化時(shí)指向 begin() ;
- thread 指向當(dāng)前線程;
- parent 指向父結(jié)點(diǎn),第一個(gè)結(jié)點(diǎn)的 parent 值為 nil ;
- child 指向子結(jié)點(diǎn),最后一個(gè)結(jié)點(diǎn)的 child 值為 nil ;
- depth 代表深度,從 0 開始,往后遞增 1;
- hiwat 代表 high water mark 。
AutoreleasePoolPage每個(gè)對(duì)象會(huì)開辟4096字節(jié)內(nèi)存(也就是虛擬內(nèi)存一頁(yè)的大小),除了實(shí)例變量所占空間,剩下的空間全部用來(lái)儲(chǔ)存autorelease對(duì)象的地址。內(nèi)存結(jié)構(gòu)如圖:

在Cocoa框架中,NSRunloop每次循環(huán)過(guò)程中NSAutoreleasePool對(duì)象被生成或廢棄。在大量產(chǎn)生autorelease對(duì)象時(shí),只要不廢棄NSAutoreleasePool那么生成的對(duì)象就不能被釋放,在此情況下有時(shí)會(huì)產(chǎn)生內(nèi)存不足的現(xiàn)象,因此有必要適當(dāng)?shù)纳?,持有和廢棄NSAutoreleasePool。通常在使用Objective-C,無(wú)論調(diào)用哪一個(gè)對(duì)象的autorelease/retain方法,實(shí)現(xiàn)上都是調(diào)用NSObject類的autorelease/retain實(shí)例方法,但是對(duì)于NSAutoreleasePool類,autorelease/retain實(shí)例方法已被重寫,因此運(yùn)行時(shí)會(huì)出錯(cuò)(exception)。autorelease實(shí)際上把對(duì)象的釋放時(shí)機(jī)交給NSAutoreleasePool管理,使用方法如下:
生成并持有NSAutoreleasePool對(duì)象。
NSAutoreleasePool *pool = [NSAutoreleasePool alloc] init]; // 等同于 objc_autoreleasePoolPush()
調(diào)用已分配對(duì)象的autorelease實(shí)例方法。
id obj = [NSObject alloc] init]; [obj autorelease]; // 等同于 objc_autorelease()obj
廢棄NSAutoreleasPool對(duì)象(自動(dòng)調(diào)用分配對(duì)象的release)。
[pool drain]; // 等同于 objc_autoreleasePoolPop(pool)
4.ARC說(shuō)明
ARC(Automatic Reference Counting)是編譯階段自動(dòng)做了retain/release,原先需要手動(dòng)添加處理引用計(jì)數(shù)的代碼可以自動(dòng)地由編譯器完成。ARC并不是GC,不是運(yùn)行時(shí)內(nèi)存管理,不會(huì)做malloc/free的工作,它只是一種代碼靜態(tài)分析(Static Analyzer)工具,同一程序中按文件單位可以選擇ARC有效和無(wú)效。Core Foundation中的malloc()或者free()等,還是需要自己手動(dòng)進(jìn)行內(nèi)存管理。設(shè)置ARC有效的編譯方法如下:
- 使用clang(LLVM編譯器)3.0或以上版本。
- 指定編譯器屬性為”-fobjc-arc“。
3.引用計(jì)數(shù)查看
Apple 提供一些方法查看對(duì)象的引用計(jì)數(shù),但是并不能完全信任這些函數(shù)提供的引用計(jì)數(shù)值。對(duì)于已釋放的對(duì)象一級(jí)不正確的對(duì)象地址,有時(shí) 也返回”1“,在多線程中,因?yàn)榇嬖诟?jìng)態(tài)條件的問(wèn)題,所以取得的的數(shù)值不一定可信。
[object retainCount]; //得到object的引用計(jì)數(shù),此方法僅僅適用于MRC _objc_rootRetainCount(obj); //MRC和ARC都適用
相關(guān)文章
iOS逆向工程使用LLDB的USB連接調(diào)試第三方App
這篇文章主要介紹了iOS逆向工程使用LLDB的USB連接調(diào)試第三方App,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
iOS移動(dòng)端軟鍵盤彈起空白和滾動(dòng)穿透問(wèn)題解決方案
這篇文章主要為大家介紹了iOS移動(dòng)端軟鍵盤彈起空白和滾動(dòng)穿透問(wèn)題解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
iOS如何用100行代碼實(shí)現(xiàn)簡(jiǎn)單的抽屜效果
最近在網(wǎng)上看到一些抽屜效果,看起來(lái)很酷!很眩!但是,下不下來(lái)看代碼, 所以決定還是自己寫吧!!這篇文章通過(guò)近100行的代碼就實(shí)現(xiàn)了簡(jiǎn)單的抽屜效果,有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-10-10
iOS使用xib手動(dòng)實(shí)現(xiàn)動(dòng)畫效果的方法
下面小編就為大家分享一篇iOS使用xib手動(dòng)實(shí)現(xiàn)動(dòng)畫效果的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
iOS App初次啟動(dòng)時(shí)的用戶引導(dǎo)頁(yè)制作實(shí)例分享
這篇文章主要介紹了iOS App初次啟動(dòng)時(shí)的用戶引導(dǎo)頁(yè)制作實(shí)例分享,其中判斷程序是否是第一次或版本更新以后第一次啟動(dòng)是一個(gè)關(guān)鍵點(diǎn),需要的朋友可以參考下2016-03-03
分析IOS RunLoop的事件循環(huán)機(jī)制
RunLoop是與線程相關(guān)的基礎(chǔ)架構(gòu)中的一部分,它是一個(gè)處理事件的循環(huán)(線程進(jìn)入這個(gè)循環(huán),運(yùn)行事件處理程序來(lái)響應(yīng)傳入的事件),RunLoop的目的是當(dāng)有事件需要處理時(shí),線程是活躍的、忙碌的,當(dāng)沒(méi)有事件后,線程進(jìn)入休眠。2021-06-06
詳解iOS應(yīng)用使用Storyboard布局時(shí)的IBOutlet與IBAction
這篇文章主要介紹了iOS應(yīng)用使用Storyboard布局時(shí)的IBOutlet與IBAction,文中還附帶講解了為什么IBOutlet屬性是weak的,需要的朋友可以參考下2016-04-04
iOS CAReplicatorLayer實(shí)現(xiàn)脈沖動(dòng)畫效果
這篇文章主要介紹了iOS CAReplicatorLayer實(shí)現(xiàn)脈沖動(dòng)畫效果 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
總結(jié)iOS開發(fā)中的斷點(diǎn)續(xù)傳與實(shí)踐
本文先從斷點(diǎn)續(xù)傳問(wèn)題開始,介紹斷點(diǎn)續(xù)傳概述和原理。接著結(jié)合筆者調(diào)研中嘗試的 AFHTTPRequestOpeartion,簡(jiǎn)單分析源碼。最后分別基于 NSURLConnection,NSURLSessionDataTask 和 NSURLSessionDownloadTask 去實(shí)現(xiàn)應(yīng)用重啟情況下的斷點(diǎn)續(xù)傳。下面一起來(lái)看看。2016-07-07

