OC Autorelease

@implementation ViewController
- (void)viewDidLoad {[super viewDidLoad];__unsafe_unretained NSObject *obj1 = [ViewController getObj];NSLog(@"=====%@",obj1); // 運行OK__unsafe_unretained NSObject *obj2 = [ViewController getObj];NSLog(@"=====%@",obj2); // crash 野指針
}+ (id)getObj {return [NSObject new];
}
復制代碼
- (void)viewDidLoad {[super viewDidLoad];__weak NSObject *obj1 = [ViewController getObj];NSLog(@"=====%@",obj1); // nil__weak NSObject *obj2 = [ViewController getObj];NSLog(@"=====%@",obj2);// 輸出對象
}
復制代碼

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/256023.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/256023.shtml
英文地址,請注明出處:http://en.pswp.cn/news/256023.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【opencv】——鋼管計數(霍夫圓變換 + 閾值 + canny)

目錄 方法一:霍夫圓變換 + canny 方法二 閾值 + 尋邊 對圖中的鋼管進行計數 方法一:霍夫圓變換 + canny

svn服務器搭建-SuSE Linux Enterprise Server 11 SP3

svn存儲版本數據也有2種方式:1.bdb;2.fsfs。因為BDB方式在服務器中斷時,有可能鎖住數據(搞ldap時就深受其害,沒法根治),所以還是FSFS方式更安全一點,我也選擇這種方式。下載相關軟件…

Swift 2.0初探:值得注意的新特性

轉眼間,Swift已經一歲多了,這門新鮮、語法時尚、類型安全、執行速度更快的語言已經漸漸的深入廣大開發者的心。我同樣也是非常喜愛這門新的編程語言。 今年6月,一年一度的WWDC大會如期而至,在大會上Apple發布了Swift 2.0&#xff…

Android 自定義WebView彈窗及屏蔽彈窗

額,還是那個WebView的問題,內核已換成騰訊X5內核,所以接下來的內容會有一些X5內核的方法。但我們的H5是不能改的,還是只有委屈我們自己。先看看H5自帶的彈窗 這樣子的彈窗在不同的手機上呈現的可能是不同的效果,效果不…

【圖像處理】——Python實現two_pass方法來進行連通域的提取

目錄 一、相關知識 1、two_pass算法思想 2、并查集算法 二、自定義的two_pass算法

C++ 多線程使用future傳遞異常

如果 std::async 調用的函數拋出異常,那么這個異常會被存儲在值的位置,同時 future 變為 ready ,如果調用 get() 會重新拋出存儲的異常。 Note: 標準并沒有指定原來的異常對象是被重新拋出或者拷貝后拋出,不同的編譯器會做不同的選擇。 對于 …

期貨黃金與現貨黃金比較

現貨黃金與期貨黃金是目前市場上最熱門的黃金投資方式,與國內任何的金融投資品相比,都具有一定的優勢。 其實金投網小編覺得現貨黃金與期貨黃金最主要的不同點是這個:期貨黃金做的是國內市場,同股票市場一樣,里面有莊家…

DNS域傳送漏洞

0x00 相關背景介紹 Dns是整個互聯網公司業務的基礎,目前越來越多的互聯網公司開始自己搭建DNS服務器做解析服務,同時由于DNS服務是基礎性服務非常重要,因此很多公司會對DNS服務器進行主備配置而DNS主備之間的數據同步就會用到dns域傳送&#…

封裝之--通過類中公有方法訪問私有成員變量

如何在ClassB中訪問ClassA的私有成員變量?(典型的封裝案例) 通過在ClassA中定義公有的成員方法,然后,在ClassB中通過ClassA的對象調用ClassA中的公有方法,來訪問ClassA中的私有成員變量。 轉載于:https://w…

匹配物鏡放大倍數與相機像元尺寸

通常來說,相機內部的CCD或者CMOS傳感器上都有感光陣列,由一個一個的感光元件構成,每一個感光元件負責完成光電轉換的過程。簡單理解,一個感光元件可以認為就是一個像素(pixel)或像元(pel)。像元具有一定尺寸,如果像的尺…

2016/11/10 kettle概述

ETL(Extract-Transform-Load,即抽取,轉換,加載),數據倉庫技術,是用來處理將數據從來源(以前做的項目)經過抽取,轉換,加載到達目的端(正在做的項目&#xff09…

【深度學習】——非極大值抑制(nms/soft-nms)

目錄 一、相關概念 1、iou 1)理論計算 2)Python代碼(代碼參考yolov3模型util.py文件) 2、nms 1)基本思路 2)標準nms和soft-nms 3)Python代碼實現(yolov3中util.py文件,增加了…

移動服務安全現狀分析!

2019獨角獸企業重金招聘Python工程師標準>>> 由于Android開源的環境,導致Android的整體環境都存在很多不安全的因素,同時用戶在移動APP客戶端的便捷應用,也給用戶帶來了巨大的安全隱患。未經過移動服務安全加固的APP存在被靜態反編…

封裝不同類模板的隨機數生成器

最近準備刷題,打算簡單封裝下隨機數生成器,方便產生測試數據。C11的STL提供了很多分布類型,我比較常用的是均勻分布,均勻分布的值有兩種類型,一類是整數,另一類是浮點數,STL根據值的類型定義了兩…

Log4j詳細設置說明

1. 動態的改變記錄級別和策略,即修改log4j.properties,不需要重啟Web應用,這需要在web.xml中設置一下。2. 把log文件定在 /WEB-INF/logs/ 而不需要寫絕對路徑。3. 可以把log4j.properties和其他properties一起放在/WEB-INF/ ,而不是Class-Pat…

【機器學習】——卷積神經網絡(Keras)修改學習率(定值+自適應)

目錄 1、直接獲取現有模型的學習率 2、打印顯示學習率 3、調整學習率 1)1.LearningRateScheduler 2)ReduceLROnPlateau 利用tensorflow的Keras模塊我們可以建立我們自己定義的卷積神經網絡模型,但是一般不會觸碰到學習率這個問題&#x…

使用Docker構建你的第一個服務

1. 感受一下Docker的便捷 項目源碼 https://github.com/MoonShining/dockernize-grape-helloworld clone下來以后運行,cd到項目目錄下,運行 docker build -t api-sample . docker run -p 8080:8080 api-sample:latest 復制代碼就可以訪問localhost:8080看到效果了. …

MyEclipse連接MySQL

在官網http://www.mysql.com/downloads/下載數據庫連接驅動 本文中使用驅動版本為mysql-connector-java-5.1.40 一、創建一個java測試項目MySQLConnectorsTest 在項目下穿件一個lib文件夾用來存放MySQL驅動包。 右鍵驅動包build path進行add添加操作,打開Referenced…

在Windows系統中配置Google AddressSanitizer

Google AddressSanitizer簡介 AddressSanitizer (ASan) 是 C 和 C 的內存錯誤檢測軟件,它可以檢測: 釋放指針后繼續使用堆緩沖區溢出棧緩沖區溢出全局緩沖區溢出返回后繼續使用在范圍之外繼續使用初始化順序的bug內存泄漏 在 Windows 系統中&#xff…

【劍指offer】——求出一個正整數的質數因子(Python)

目錄 一、題目描述 二、思路 1、短除法 2、平方根法 一、題目描述 功能:輸入一個正整數,按照從小到大的順序輸出它的所有質因子(重復的也要列舉)(如180的質因子為2 2 3 3 5 ) 最后一個數后面也要有空格 輸入描述…