日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OC Autorelease

發(fā)布時(shí)間:2023/12/10 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OC Autorelease 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
@implementation ViewController - (void)viewDidLoad {[super viewDidLoad];__unsafe_unretained NSObject *obj1 = [ViewController getObj];NSLog(@"=====%@",obj1); // 運(yùn)行OK__unsafe_unretained NSObject *obj2 = [ViewController getObj];NSLog(@"=====%@",obj2); // crash 野指針 }+ (id)getObj {return [NSObject new]; } 復(fù)制代碼- (void)viewDidLoad {[super viewDidLoad];__weak NSObject *obj1 = [ViewController getObj];NSLog(@"=====%@",obj1); // nil__weak NSObject *obj2 = [ViewController getObj];NSLog(@"=====%@",obj2);// 輸出對象 } 復(fù)制代碼

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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。