


indexed標識isa是否僅僅為一個內(nèi)存指針,如果為1的話就僅是一個內(nèi)存指針,如果為0的話則意味著內(nèi)存的64位不僅僅用于存儲內(nèi)存指針
has_assoc代表該對象是否有關聯(lián)屬性
has_cxx_dtor代表對象是否有和c++相關的屬性
shiftcls代表對象實際的內(nèi)存地址
weakly_referenced代表對象是否有弱引用指向
deallocating標識對象是否正在被銷毀
has_sidetable_rc代表對象是否有額外的引用計數(shù)表
extra_rc代表對象的引用計數(shù)(當對象的引用計數(shù)很小的時候對象的引用計數(shù)就記錄在當前對象的isa指針中)


為什么不是一個sidetable呢??
如果只有一個表的話系統(tǒng)的操作對象的引用計數(shù)時其他的對象就在等待,這就降低了效率 。

使用64張table存儲的話就能實現(xiàn)并發(fā)操作。

自旋鎖是循環(huán)訪問的機制,只適用于輕量訪問的情況。

引用計數(shù)表的前兩位分別標識該對象是否有弱引用以及是否處于正在銷毀狀態(tài),所以計算引用計數(shù)時要向右偏移兩位

弱引用表是一張Hash表,key為當前對象的指針地址,vlaue為指向當前對象的弱引用對象鏈表
MRC和ARC的區(qū)別


ARC的本質是編譯器和Runtime協(xié)作的結果

引用計數(shù)的管理機制

alloc的時候并沒有將對象的引用計數(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的實現(xiàn):先在sidetables表集合中根據(jù)對象的指針地址找到對應的sidetable,再sidetable中的通過hash查找找到對象對應的引用計數(shù),如果當前的表中對象是新建的話,此時hash表中的it->second為0,返回默認值累加值1.
如果不為0,則將對應數(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);
}
對象的調(diào)用dealloc后的銷毀過程

要判斷對象是否有isa指針,弱引用,關聯(lián)對象,c++相關和引用計數(shù)表并對應執(zhí)行銷毀操作。

object_dispose 實現(xiàn)

objc_destructInstance實現(xiàn)

銷毀c++和關聯(lián)對象后再銷毀對象的引用計數(shù)和弱引用


弱引用初始化時Runtime會調(diào)用obc_initWeak函數(shù)初始化一個新的weak指針指向對象,經(jīng)過objc_storeWeak調(diào)整參數(shù),最終由weak_register_no_lock創(chuàng)建弱引用鏈表存儲對象的指針。
image.png
image.png
清除weak變量并設置nil的過程如下

釋放時,調(diào)用sidetable_clearDeallocating函數(shù),然后調(diào)用weak_clear_no_lock()根據(jù)對象的地址獲取到為weak表中的指向該對象的弱指針數(shù)組,遍歷數(shù)組將數(shù)組中的所有項都設置為nil,最后把entry從weak表中刪除。
總結一下 添加weak變量中會調(diào)用 initWeak(),storeWeak(),weak_register_no_lock()函數(shù)。清除weak變量置nil會調(diào)用learDeallocating(),weak_clear_no_lock()函數(shù)。在添加和刪除的過程中都不斷的使用hash查找定位變量在weak表中的位置。
自動釋放池autoreleasePool
問題1.圖中的array是什么時候被釋放的??
在每次runloop開始都會調(diào)用一次autoreleasePoolPush操作,每次runloop結束的時候都會調(diào)用一次autoreleasePoolPop操作,array就是在pop操作的過程中被release釋放。

問題2.autoreleasePool的實現(xiàn)原理是什么??
問題3.autoreleasePool是如何實現(xiàn)嵌套使用的??
問題4.在實際開發(fā)過程中autoreleasePool的應用場景是怎樣的??

在實際的開發(fā)過程中@autoreleasePool{}會被改寫成下圖的代碼會在要執(zhí)行的代碼前后分別加上autoreleasePoolPush和autoreleasePoolPop



autoreleasePoolPage的本質是以棧為節(jié)點通過雙向鏈表的形式組合而成結構體,而且autoreleasePoolPage與具體的線程相關聯(lián)

autoreleasePoolPush操作是向autoreleasePoolPage棧中插入哨兵對象標識本次的autorelease開始存儲數(shù)據(jù)位置,autoreleasePoolPop首先找到相應的autoreleasePoolPage并對棧進行出棧操作,每出棧一個對象的同時會調(diào)用對象的release方法直到出棧至最上方的哨兵對象停止出棧。















NSTimer產(chǎn)生循環(huán)引用的原因和解決方案
[NSTimer scheduledTimerWithTimeInterval:interval target:object selector:@selector(fire:) userInfo:userInfo repeats:repeats];
NSTimer注冊到當前線程的runloop中后 當前的runloop會持有timer的強引用,同時timer強引用當前對象形成環(huán)引用。

解決方法:在timer和object中間添加中間對象,中間對象分別弱引用timer和object,在每次執(zhí)行timer的方法時都判斷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

