一.內(nèi)存布局
1.stack:方法調(diào)用
2.heap:通過alloc等分配的對(duì)象
3.bss:未初始化的全局變量和未初始化的靜態(tài)變量等
4.data:已初始化的全局變量和已初始化的靜態(tài)變量等
5.text:程序的代碼段
二柑船、內(nèi)存管理方案
OC針對(duì)于不同場(chǎng)景的管理方案
1.TaggedPointer:針對(duì)小對(duì)象(NSNumber等)
2.NONPOINTER_ISA:針對(duì)64位架構(gòu)下的ios應(yīng)用程序擎颖,isa占64bit的羞反,實(shí)際上32bit或者40bit就夠用了科吭,其他的為了提升利用率,用于內(nèi)存管理方面的相關(guān)內(nèi)容浑此,所以說(shuō)這叫非指針型的isa
3.散列表:是一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)(包括了引用計(jì)數(shù)表累颂,和弱引用表)
散列表的實(shí)現(xiàn)方案是通過SideTables方案來(lái)實(shí)現(xiàn)的,在不同的系統(tǒng)下SideTables的SideTable是有不同的個(gè)數(shù)的,在非嵌入式系統(tǒng)下有64個(gè)尤勋。入下圖所示
三、MRC
1.alloc:給對(duì)想分配內(nèi)存空間 (實(shí)現(xiàn):1.經(jīng)過一系列函數(shù)的封裝和調(diào)用茵宪,最終調(diào)用了c函數(shù)的calloc最冰。2.此時(shí)并沒有設(shè)置引用計(jì)數(shù)加1)
2.retain:引用計(jì)數(shù)加1
retain實(shí)現(xiàn):
SideTable& table = SideTables()[this] ;
size_t& refcntStorage = table.refcnts[this];
refcntStorage += SIDE_TABLE_RC_ONE;
通過兩次Hash查找,查到當(dāng)前對(duì)象引用計(jì)數(shù)表稀火,執(zhí)行加1造作
3.release:引用計(jì)數(shù)減1
release實(shí)現(xiàn)
SideTable& table = SideTables()[this] ;
RefcountMap::iterator it= table.refcnts.find(this);
it->sencont -= SIDE_TABLE_RC_ONE;
4.retainCount:獲取當(dāng)前對(duì)象的引用計(jì)數(shù)值
retainCount實(shí)現(xiàn)
SideTable& table = SideTables()[this] ;
size_t refcnt_result = 1;
RefcountMap::iterator it = table.refcnts.find(this);
refcnt_result +=?it->sencont >> SIDE_TABLE_RC_SHIFT;
5.autorelease:如果當(dāng)前對(duì)象調(diào)用了autorelease操作會(huì)在autoreleasepool結(jié)束的時(shí)候會(huì)調(diào)用release操作進(jìn)行引用計(jì)數(shù)減1
6.dealloc:顯式調(diào)用super.dealloc來(lái)釋放或者廢棄父類的相關(guān)成員變量
nonpointer_isa:非指針型isa
weakly_referenced:當(dāng)前對(duì)象是否有weak指針指向它
hea_assoc:當(dāng)前對(duì)象是否有關(guān)聯(lián)對(duì)象
has_cxx_dtor:判斷當(dāng)前對(duì)象內(nèi)部實(shí)現(xiàn)是否有c++實(shí)現(xiàn)的內(nèi)容以及當(dāng)前對(duì)象是否使用ARC來(lái)管理內(nèi)存
has_sidtable_rc:當(dāng)前對(duì)象是否通過sidetable引用計(jì)數(shù)表來(lái)維護(hù)的
free():C函數(shù)清理內(nèi)存
objc_destructInstance()實(shí)現(xiàn)
clearDeallocation()實(shí)現(xiàn)
四暖哨、ARC
1.ARC其實(shí)是編譯器自動(dòng)添加retain和release之外還需要runtime功能進(jìn)行支持,然后由LLVM編譯器和runtime協(xié)作才能組成ARC全部的功能
2.ARC中禁止手動(dòng)調(diào)用retain/release/retainCount/dealloc(可以重寫dealloc凰狞,但是不能顯式調(diào)用super.dealloc)
3.ARC中新增了weak篇裁、和Strong屬性關(guān)鍵字
五、弱引用管理
1.系統(tǒng)是怎樣把一個(gè)weak變量添加到它對(duì)應(yīng)的弱引用表當(dāng)中的赡若?
一個(gè)被聲明__weak的對(duì)象指針达布,經(jīng)過編譯器編譯之后,會(huì)調(diào)用objc_initWeak() 函數(shù)逾冬,經(jīng)過一系列函數(shù)調(diào)用黍聂,會(huì)在weak_register_no_lock()函數(shù)當(dāng)中進(jìn)行弱引用添加,具體添加的位置是通過一個(gè)hash算法來(lái)查找的身腻,如果查找的當(dāng)前對(duì)象已經(jīng)有了弱引用對(duì)象數(shù)組产还,就把新的弱引用對(duì)象添加到弱引用數(shù)組中,如果沒有的話從新創(chuàng)建一個(gè)弱引用數(shù)組然后把第0個(gè)位置添加上弱引用指針
2.面試題:當(dāng)一個(gè)對(duì)象被廢棄后嘀趟,weak變量為什么會(huì)被置為nil
當(dāng)一個(gè)對(duì)象被dealloc之后脐区,在dealloc內(nèi)部實(shí)現(xiàn)當(dāng)中會(huì)調(diào)用弱引用清除的函數(shù)weak_clear_no_lock(), 在該函數(shù)的內(nèi)部實(shí)現(xiàn)當(dāng)中根據(jù)當(dāng)前對(duì)象指針查找當(dāng)前對(duì)象相對(duì)應(yīng)的的弱引用把當(dāng)前對(duì)象的弱引用都拿出來(lái)形成一個(gè)數(shù)組,遍歷弱應(yīng)用數(shù)組當(dāng)中所有的弱引用指針分別置為nil
六她按、自動(dòng)釋放池
AutoreleasePoolPage::push的實(shí)現(xiàn)原理:next指向一個(gè)空地址牛隅,在調(diào)用AutoreleasePoolPage::push的時(shí)候會(huì)在next指向的空地址添加一個(gè)哨兵對(duì)象炕柔,next指針指向下一個(gè)可入棧的位置
AutoreleasePoolPage::pop實(shí)現(xiàn)原理:根據(jù)傳入的哨兵對(duì)象找到正確的位置,給上次push操作之后添加的對(duì)象依次是發(fā)送release消息倔叼,然后回退next指針到正確的位置汗唱。
1.AutoreleasePool的實(shí)現(xiàn)原理是什么?
是以棧為節(jié)點(diǎn)通過雙向鏈表的形式組合而成
2.AutoreleasePool為何可以嵌套使用丈攒?
多層嵌套就是多次插入哨兵對(duì)象哩罪,每次進(jìn)行@Autorelease代碼塊創(chuàng)建的時(shí)候系統(tǒng)就會(huì)為我們進(jìn)行一個(gè)哨兵對(duì)象的插入,然后完成一個(gè)新的autorelease創(chuàng)建
3.什么是自動(dòng)釋放池或者說(shuō)自動(dòng)釋放池的結(jié)構(gòu)是怎樣的巡验?
是以棧為節(jié)點(diǎn)通過雙向鏈表的形式組合而成
在for循環(huán)中alloc圖片數(shù)據(jù)等內(nèi)存消耗較大的場(chǎng)景手動(dòng)插入autoreleasePool每次for循環(huán)都進(jìn)行一次內(nèi)存釋放來(lái)降低內(nèi)存的峰值际插,防止內(nèi)存過大所導(dǎo)致的一些問題。