OC Autorelease
Autorelease與Autoreleasepool
參考: ARC環(huán)境下編譯器到底對autorelease對象做了怎樣的優(yōu)化 黑幕背后的Autorelease 自動釋放池的前世今生 ---- 深入解析 Autoreleasepool Objective-C 小記(8)autorelease
####autoreleasepool 1、自動釋放池是由 AutoreleasePoolPage 以雙向鏈表的方式實(shí)現(xiàn)的 2、當(dāng)對象調(diào)用 autorelease 方法時(shí),會將對象加入 AutoreleasePoolPage 的棧中 3、調(diào)用 AutoreleasePoolPage::pop 方法會向棧中的對象發(fā)送 release 消息 @autoreleasepool{}
@autoreleasepool {__autoreleasing NSObject *obj = [NSObject new];} 復(fù)制代碼偽代碼
// 獲取哨兵POOL_SENTINELvoid * atautoreleasepoolobj = objc_autoreleasePoolPush();{__autoreleasing NSObject *obj = [NSObject new];}// 就是release哨兵之后的autorelease對象。objc_autoreleasePoolPop(atautoreleasepoolobj); 復(fù)制代碼autorelease調(diào)用棧
- [NSObject autorelease] └── id objc_object::rootAutorelease()└─ id objc_object::rootAutorelease2()└─ static id AutoreleasePoolPage::autorelease(id obj)└─ static id AutoreleasePoolPage::autoreleaseFast(id obj)├─ id *add(id obj)├─ static id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page)│ ├─ AutoreleasePoolPage(AutoreleasePoolPage *newParent)│ └─ id *add(id obj)└─ static id *autoreleaseNoPage(id obj)├─ AutoreleasePoolPage(AutoreleasePoolPage *newParent)└─ id *add(id obj) 復(fù)制代碼#####一個(gè)autorelease對象在什么時(shí)刻釋放? 1、手動指定Autoreleasepool:當(dāng)前Autoreleasepool作用域大括號結(jié)束時(shí)釋放;
2、不手動指定:autorelease對象會被添加到最近一次創(chuàng)建的autoreleasepool中,并在當(dāng)前的runloop迭代結(jié)束時(shí)候釋放。
例如:主Runloop對Autoreleasepool管理的流程: Runloop中,檢測到觸摸事件,創(chuàng)建事件,創(chuàng)建Autoreleasepool,autorelease對象加入pool中,事件完成,Runloop運(yùn)行循環(huán)將要結(jié)束,釋放Autoreleasepool,向pool中對象發(fā)送release消息,Runloop休眠。 ####autorelease 進(jìn)行的非持有方法的優(yōu)化 1、alloc/new/copy/mutableCopy---持有對象方法 2、其他類方法返回的對象,如果下面的createObj
@implementation BBObject + (instancetype)createObj {return [self new]; } 復(fù)制代碼需要了解下面的方法:
id objc_autoreleaseReturnValue(id obj) {// prepareOptimizedReturn判斷是否可以TSL優(yōu)化,可以則標(biāo)記,YES--就不需要調(diào)用 objc_autorelease(),優(yōu)化性能if (prepareOptimizedReturn(ReturnAtPlus1)) return obj;return objc_autorelease(obj); } id objc_retainAutoreleasedReturnValue(id obj) {// 如果之前 objc_autoreleaseReturnValue() 存入的標(biāo)志位為 ReturnAtPlus1,則直接返回對象,無需調(diào)用 objc_retain(),優(yōu)化性能if (acceptOptimizedReturn() == ReturnAtPlus1) return obj;return objc_retain(obj); } 復(fù)制代碼static ALWAYS_INLINE bool prepareOptimizedReturn(ReturnDisposition disposition) {assert(getReturnDisposition() == ReturnAtPlus0);if (callerAcceptsOptimizedReturn(__builtin_return_address(0))) {if (disposition) setReturnDisposition(disposition);return true;}return false; }static ALWAYS_INLINE ReturnDisposition acceptOptimizedReturn() {ReturnDisposition disposition = getReturnDisposition();setReturnDisposition(ReturnAtPlus0); // reset to the unoptimized statereturn disposition; } 復(fù)制代碼TLS 全稱為 Thread Local Storage,是每個(gè)線程專有的鍵值存儲
在某個(gè)線程上的函數(shù)調(diào)用棧上相鄰兩個(gè)函數(shù)對 TLS 進(jìn)行了存取,這中間肯定不會有別的程序『插手』。 所以 getReturnDisposition() 和 setReturnDisposition() 的實(shí)現(xiàn)比較簡單,不需要判斷考慮是針對哪個(gè)對象的 Disposition 進(jìn)行存取,因?yàn)楫?dāng)前線程上下文中只處理唯一的對象,保證不會亂掉。 static ALWAYS_INLINE void setReturnDisposition(ReturnDisposition disposition) {tls_set_direct(RETURN_DISPOSITION_KEY, (void*)(uintptr_t)disposition); } 復(fù)制代碼callerAcceptsOptimizedReturn(__builtin_return_address(0))函數(shù)在不同架構(gòu)的 CPU 上實(shí)現(xiàn)也是不一樣的。 主要作用:
__builtin_return_address(0)獲取當(dāng)前函數(shù)返回地址,傳入 callerAcceptsOptimizedReturn 判斷調(diào)用方是否緊接著調(diào)用了 objc_retainAutoreleasedReturnValue 當(dāng)判斷調(diào)用方緊接著調(diào)用了 objc_retainAutoreleasedReturnValue 或者 objc_unsafeClaimAutoreleasedReturnValue 直接當(dāng)前對象地址,而不執(zhí)行retain與autorelease操作.
#####ARC 會視情況在調(diào)用方法時(shí)可能會添加 retain ,在方法內(nèi)部返回時(shí)可能會添加 autorelease ,經(jīng)過優(yōu)化后很可能會抵消。
#####1、持有、無引用 - (void)test {[BBObject new]; } 復(fù)制代碼編譯器編譯后的偽代碼
- (void)test {objc_release([BBObject new]) ; } 復(fù)制代碼#####2、持有、局部變量引用 __strong
- (void)test {__strong BBObject * obj = [BBObject new]; } 復(fù)制代碼編譯器編譯后的偽代碼
- (void)test {id temp = [BBObject new];objc_storeStrong(&tmp,nil);//相當(dāng)于tmp指向?qū)ο髨?zhí)行release } 復(fù)制代碼__weak、__unsafe_unretained
// 這種寫法xcode提示警告__weak BBObject * obj = [BBObject new]; __unsafe_unretained BBObject * obj = [BBObject new]; 復(fù)制代碼#####3、持有、外部變量引用
- (void)test {self.obj = [BBObject new]; } 復(fù)制代碼編譯器編譯后的偽代碼
- (void)test{id temp = [BBObject new];[self setObj:temp];//setter方法執(zhí)行objc_storeStrongobjc_release(temp); } - (void)setObj:(id aObj) {objc_storeStrong(&_obj, aObj); } 復(fù)制代碼#####4、不持有、無引用
- (void)test {[BBObject createObj]; } 復(fù)制代碼編譯器編譯后的偽代碼
+ (instancetype) createObj {id tmp = [self new];return objc_autoreleaseReturnValue(tmp); // 系統(tǒng)可能會調(diào)用[tmp autorelease] } - (void)test { objc_unsafeClaimAutoreleasedReturnValue([BBObject createObj]); } 復(fù)制代碼#####5、不持有、局部變量引用
- (void)test {BBObject * obj1 = [BBObject createObj]; } 復(fù)制代碼編譯器編譯后的偽代碼
+ (instancetype) createObj {id tmp = [self new];return objc_autoreleaseReturnValue(tmp); // 系統(tǒng)可能會調(diào)用[tmp autorelease] } - (void)test {id obj1 = objc_retainAutoreleasedReturnValue([BBObject createObj]); objc_storeStrong(& obj1,nil); } 復(fù)制代碼發(fā)現(xiàn)obj1指向的對象不會加入autoreleasepool
#####6、不持有、外部變量引用
+ (instancetype) createObj {id tmp = [self new];return objc_autoreleaseReturnValue(tmp); // 系統(tǒng)可能會調(diào)用[tmp autorelease] } - (void)test {self.obj = [BBObject createObj]; } 復(fù)制代碼編譯后的偽代碼
- (void)test {id tmp = _objc_retainAutoreleasedReturnValue([Foo createFoo]); [self setObj:temp]; // setter方法執(zhí)行objc_storeStrongobjc_release(temp); } 復(fù)制代碼查看autoreleasepool中的對象方法: 1、extern void _objc_autoreleasePoolPrint(void); //extern這個(gè)方法,需要查看的地方使用_objc_autoreleasePoolPrint();
2、需要查看的地方打斷點(diǎn),然后po _objc_autoreleasePoolPrint()
轉(zhuǎn)載于:https://juejin.im/post/5a312182f265da4304069e3d
總結(jié)
以上是生活随笔為你收集整理的OC Autorelease的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 隐藏该监视器无法显示模式_【春星开讲 |
- 下一篇: c语言分量的运算符,C语言基础(04-运