indexed標(biāo)識(shí)isa是否僅僅為一個(gè)內(nèi)存指針祭阀,如果為1的話就僅是一個(gè)內(nèi)存指針专控,如果為0的話則意味著內(nèi)存的64位不僅僅用于存儲(chǔ)內(nèi)存指針
has_assoc代表該對(duì)象是否有關(guān)聯(lián)屬性
has_cxx_dtor代表對(duì)象是否有和c++相關(guān)的屬性
shiftcls代表對(duì)象實(shí)際的內(nèi)存地址
weakly_referenced代表對(duì)象是否有弱引用指向
deallocating標(biāo)識(shí)對(duì)象是否正在被銷毀
has_sidetable_rc代表對(duì)象是否有額外的引用計(jì)數(shù)表
extra_rc代表對(duì)象的引用計(jì)數(shù)(當(dāng)對(duì)象的引用計(jì)數(shù)很小的時(shí)候?qū)ο蟮囊糜?jì)數(shù)就記錄在當(dāng)前對(duì)象的isa指針中)
為什么不是一個(gè)sidetable呢赢底?幸冻?
如果只有一個(gè)表的話系統(tǒng)的操作對(duì)象的引用計(jì)數(shù)時(shí)其他的對(duì)象就在等待辩越,這就降低了效率 黔攒。
使用64張table存儲(chǔ)的話就能實(shí)現(xiàn)并發(fā)操作不傅。
自旋鎖是循環(huán)訪問(wèn)的機(jī)制访娶,只適用于輕量訪問(wèn)的情況崖疤。
引用計(jì)數(shù)表的前兩位分別標(biāo)識(shí)該對(duì)象是否有弱引用以及是否處于正在銷毀狀態(tài)劫哼,所以計(jì)算引用計(jì)數(shù)時(shí)要向右偏移兩位
弱引用表是一張Hash表权烧,key為當(dāng)前對(duì)象的指針地址般码,vlaue為指向當(dāng)前對(duì)象的弱引用對(duì)象鏈表
MRC和ARC的區(qū)別
ARC的本質(zhì)是編譯器和Runtime協(xié)作的結(jié)果
引用計(jì)數(shù)的管理機(jī)制
alloc的時(shí)候并沒(méi)有將對(duì)象的引用計(jì)數(shù)設(shè)置為1,而是retain的初始值為1
objc_object::sidetable_retainCount()
{
SideTable& table = SideTables()[this];
size_t refcnt_result = 1;
table.lock();
RefcountMap::iterator it = table.refcnts.find(this);
if (it != table.refcnts.end()) {
// this is valid for SIDE_TABLE_RC_PINNED too
refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;
}
table.unlock();
return refcnt_result;
}
retainCount的實(shí)現(xiàn):先在sidetables表集合中根據(jù)對(duì)象的指針地址找到對(duì)應(yīng)的sidetable囊嘉,再sidetable中的通過(guò)hash查找找到對(duì)象對(duì)應(yīng)的引用計(jì)數(shù),如果當(dāng)前的表中對(duì)象是新建的話震檩,此時(shí)hash表中的it->second為0抛虏,返回默認(rèn)值累加值1.
如果不為0迂猴,則將對(duì)應(yīng)數(shù)值向右偏移兩位后加1.
id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.indexed);
#endif
SideTable& table = SideTables()[this];
if (table.trylock()) {
size_t& refcntStorage = table.refcnts[this];
if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
refcntStorage += SIDE_TABLE_RC_ONE;
}
table.unlock();
return (id)this;
}
return sidetable_retain_slow(table);
}
對(duì)象的調(diào)用dealloc后的銷毀過(guò)程
要判斷對(duì)象是否有isa指針,弱引用息尺,關(guān)聯(lián)對(duì)象搂誉,c++相關(guān)和引用計(jì)數(shù)表并對(duì)應(yīng)執(zhí)行銷毀操作炭懊。
object_dispose 實(shí)現(xiàn)
objc_destructInstance實(shí)現(xiàn)
銷毀c++和關(guān)聯(lián)對(duì)象后再銷毀對(duì)象的引用計(jì)數(shù)和弱引用
弱引用初始化時(shí)Runtime會(huì)調(diào)用obc_initWeak函數(shù)初始化一個(gè)新的weak指針指向?qū)ο螅?jīng)過(guò)objc_storeWeak調(diào)整參數(shù)凯旋,最終由weak_register_no_lock創(chuàng)建弱引用鏈表存儲(chǔ)對(duì)象的指針至非。
image.png
image.png
清除weak變量并設(shè)置nil的過(guò)程如下
釋放時(shí)谐鼎,調(diào)用sidetable_clearDeallocating函數(shù)狸棍,然后調(diào)用weak_clear_no_lock()根據(jù)對(duì)象的地址獲取到為weak表中的指向該對(duì)象的弱指針數(shù)組草戈,遍歷數(shù)組將數(shù)組中的所有項(xiàng)都設(shè)置為nil唐片,最后把entry從weak表中刪除涨颜。
總結(jié)一下 添加weak變量中會(huì)調(diào)用 initWeak()庭瑰,storeWeak()弹灭,weak_register_no_lock()函數(shù)穷吮。清除weak變量置nil會(huì)調(diào)用learDeallocating()酒来,weak_clear_no_lock()函數(shù)。在添加和刪除的過(guò)程中都不斷的使用hash查找定位變量在weak表中的位置辽社。
自動(dòng)釋放池autoreleasePool
問(wèn)題1.圖中的array是什么時(shí)候被釋放的滴铅?汉匙?
在每次runloop開(kāi)始都會(huì)調(diào)用一次autoreleasePoolPush操作噩翠,每次runloop結(jié)束的時(shí)候都會(huì)調(diào)用一次autoreleasePoolPop操作伤锚,array就是在pop操作的過(guò)程中被release釋放屯援。
問(wèn)題2.autoreleasePool的實(shí)現(xiàn)原理是什么狞洋?吉懊?
問(wèn)題3.autoreleasePool是如何實(shí)現(xiàn)嵌套使用的惕它?淹魄?
問(wèn)題4.在實(shí)際開(kāi)發(fā)過(guò)程中autoreleasePool的應(yīng)用場(chǎng)景是怎樣的堡距?羽戒?
在實(shí)際的開(kāi)發(fā)過(guò)程中@autoreleasePool{}會(huì)被改寫成下圖的代碼會(huì)在要執(zhí)行的代碼前后分別加上autoreleasePoolPush和autoreleasePoolPop
autoreleasePoolPage的本質(zhì)是以棧為節(jié)點(diǎn)通過(guò)雙向鏈表的形式組合而成結(jié)構(gòu)體,而且autoreleasePoolPage與具體的線程相關(guān)聯(lián)
autoreleasePoolPush操作是向autoreleasePoolPage棧中插入哨兵對(duì)象標(biāo)識(shí)本次的autorelease開(kāi)始存儲(chǔ)數(shù)據(jù)位置,autoreleasePoolPop首先找到相應(yīng)的autoreleasePoolPage并對(duì)棧進(jìn)行出棧操作企量,每出棧一個(gè)對(duì)象的同時(shí)會(huì)調(diào)用對(duì)象的release方法直到出棧至最上方的哨兵對(duì)象停止出棧届巩。
NSTimer產(chǎn)生循環(huán)引用的原因和解決方案
[NSTimer scheduledTimerWithTimeInterval:interval target:object selector:@selector(fire:) userInfo:userInfo repeats:repeats];
NSTimer注冊(cè)到當(dāng)前線程的runloop中后 當(dāng)前的runloop會(huì)持有timer的強(qiáng)引用方咆,同時(shí)timer強(qiáng)引用當(dāng)前對(duì)象形成環(huán)引用瓣赂。
解決方法:在timer和object中間添加中間對(duì)象煌集,中間對(duì)象分別弱引用timer和object苫纤,在每次執(zhí)行timer的方法時(shí)都判斷oject是否存在,存在則調(diào)用方法不存在則消除timer
#import "NSTimer+WeakTimer.h"
@interface TimerWeakObject : NSObject
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL selector;
@property (nonatomic, weak) NSTimer *timer;
- (void)fire:(NSTimer *)timer;
@end
@implementation TimerWeakObject
- (void)fire:(NSTimer *)timer
{
if (self.target) {
if ([self.target respondsToSelector:self.selector]) {
[self.target performSelector:self.selector withObject:timer.userInfo];
}
}
else{
[self.timer invalidate];
}
}
@end
@implementation NSTimer (WeakTimer)
+ (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)interval
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats
{
TimerWeakObject *object = [[TimerWeakObject alloc] init];
object.target = aTarget;
object.selector = aSelector;
object.timer = [NSTimer scheduledTimerWithTimeInterval:interval target:object selector:@selector(fire:) userInfo:userInfo repeats:repeats];
return object.timer;
}
@end