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