MRC&ARC
ARC是LLVM和Runtime配合的結(jié)果
ARC中禁?止?手動調(diào)?用retain/release/retainCount/dealloc
ARC新加了了weak、strong屬性關(guān)鍵字
alloc出來的引用計數(shù)是多少?
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *p = [LGPerson alloc];
NSLog(@"%lu",(unsigned long)[p retainCount]);
}
return 0;
}
打印出的結(jié)果是1
這個時候 我們?nèi)ゲ榭磖etainCount的底層
RetainCount
全局搜索retainCount


由retainCount源碼看出返回的rc是isa.bits.extra_rc + 1所得到的 再次 因為打印出來的結(jié)果是1 那么就認為isa.bits.extra_rc = 0 也就是該對象的引用計數(shù)在alloc之后是0
引用計數(shù)在什么時候會加 什么時候會減
Retain
全局搜索retain




引用計數(shù)表的前兩位存的不是引用計數(shù) 第一位存的是是否為弱引用的標識 第二位存的是是否正在deallocating
Release
當引用計數(shù)為0的時候 會走析構(gòu)方法 這個是必要條件 不是充分條件
全局搜索release



如果走析構(gòu)函數(shù) 就會給這個對象發(fā)送dealloc消息
release是先對isa.bits.extra_rc進行減一操作 如果沒有下溢出的話就結(jié)束
如果有下溢出的話 就去查看散列表是否存放了引用計數(shù) 如果有的話 就取出散列表中存放的那一半空間的引用計數(shù)進行減一操作然后存放到extra_rc中 結(jié)束
如果散列表中沒有存放引用計數(shù) 就發(fā)送dealloc消息
為什么當引用計數(shù)超的時候 放一半到散列表?
1 當extra_rc都存放滿的時候 如果全部放到散列表中 等下次extra_rc滿了 再次放到散列表 會造成當對這個對象進行release操作的時候 由于extra_rc沒有值的話 就會對散列表進行操作 造成對散列表的操作過于頻繁 從而影響到性能
2 一半正好是位移操作的一個位置 便于直接簡單操作 左移右移一位 能夠直接定位
3. 不大不小 正好合適 對于retain release來說
retain 相應的引用計數(shù)加1
release 相應的引用計數(shù)減一
dealloc應該做一些什么事情
weak

全局搜索objc_initWeak

如果弱引用表中有weak對象 就remove



如果弱引用表中沒有weak對象
1.就進行weak_register_no_lock操作

2.創(chuàng)建entry
@如果weak_entries不存在的話 就直接返回
如果存在的話 就找到那個原先沒有存放過entry的位置 返回這個位置的entry

如果這個entry是存在的話 就執(zhí)行append_referrer(entry, referrer);方法
在這個方法中 就是把這個弱引用的指針存放在entry的inline_referrers數(shù)組,同時要把這個弱引用的指針存放在new_referrers數(shù)組里面 也要賦值給entry的referrers變量
3.如果entry無法創(chuàng)建的話

@新建一個entry
@如果weakTable的entrys里面存放的值的大小的3/4已經(jīng)達到了weakTable設置的num_entryies的大小 那么久會擴容

@然后把entry加入到weak_entries里面 同時num_entries進行加一操作

有一步操作需要注意: 在新建entry的時候?qū)λ膇nline_referrers數(shù)組進行了初始化 把weak對象和entry聯(lián)系起來了
weak對引用計數(shù)不操作
1:拿到sideTable
2:得到sideTable的weakTable 弱引?用表
3:創(chuàng)建?一個weak_entry_t
4:把referent加?入到weak_entry_t的數(shù)組inline_referrers
5:把weak_table擴容?一下
6:把new_entry加?入到weak_table中
dealloc
全局搜索dealloc

如果他沒有弱引用 沒有關(guān)聯(lián)對象 沒有c++函數(shù) 散列表里面沒有放引用計數(shù)的話 直接free 否則 object_dispose

如果有C++函數(shù) 或者如果有關(guān)聯(lián)對象 直接remove 然后再執(zhí)行clearDeallocating






1:根據(jù)當前對象的狀態(tài)是否直接調(diào)?用free()釋放
2:是否存在C++的析構(gòu)函數(shù)、移除這個對象的關(guān)聯(lián)屬性
3:將指向該對象的弱引?用指針置為nil
4:從弱引?用表中擦除對該對象的引?用計數(shù)
Strong
全局搜索objc_storeStrong
retain新值 release舊值

objc_ivar_memoryUnretained不是指針的傳遞 是對象的傳遞 也就說value為nil的話
*location 就是野指針 浪費空間 這就是unsafe不安全的原因

自動釋放池
自動釋放池: 容納變量 在合適的位置釋放
在何時使用?
1.大量的臨時變量
2.非UI操作 命令行代碼
3.自己創(chuàng)建輔助線程
查看cpp代碼
1.cd 到main存在的目錄
2.終端執(zhí)行clang -rewrite-objc main.m -o main.cpp
3.打開main.cpp
struct __AtAutoreleasePool {
//產(chǎn)生一個atautoreleasepoolobj對象
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
//析構(gòu)函數(shù)
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
全局搜索objc_autoreleasePoolPush

autoreleasePoolPage 屬性占用的字節(jié)為56個



一頁所能容納的大小 是 4096





一共可以容納4096個字節(jié) 減掉本身占用的56個字節(jié) 剩下4040個字節(jié) 每個變量占用8個字節(jié) 也就是可以容納505個
全局搜索_objc_autoreleasePoolPrint



4096個大小 有56個屬性 進行壓棧之前要開辟一個邊界符然后繼續(xù)壓棧 直到這個頁面滿了之后 開辟新的頁面 還是要先開辟一個邊界符
autorelease
全局搜索autorelease {

直接執(zhí)行autoreleaseFast方法


Push
1.有頁面但是滿了 - 創(chuàng)建新的頁面 老頁面的child指針指向新的頁面 新界面的parent指針指向老頁面
2.有頁面但是沒有滿 直接加入進去
3.一個頁面都沒有 創(chuàng)建新的界面
都執(zhí)行add(objc) *next++ = objc
pop
全局搜索pop


id obj = *--page->next;
都執(zhí)行release(objc)
