+ (instancetype)createSark {
return [self new];
}
// caller
Sark *sark = [Sark createSark];
編譯器改寫成了形如下面的代碼:
+ (instancetype)createSark {
id tmp = [self new];
return objc_autoreleaseReturnValue(tmp); // 代替我們調用autorelease
}
// caller
id tmp = objc_retainAutoreleasedReturnValue([Sark createSark]) // 代替我們調用retain
Sark *sark = tmp;
objc_storeStrong(&sark, nil); // 相當于代替我們調用了release
runtime使用了一些黑魔法進行了優化
Thread Local Storage
Thread Local Storage(TLS)線程局部存儲,目的很簡單,将一塊記憶體作為某個線程專有的存儲,以key-value的形式進行讀寫,比如在非arm架構下,使用pthread提供的方法實作:
void* pthread_getspecific(pthread_key_t);
int pthread_setspecific(pthread_key_t , const void *);
在傳回值身上調用objc_autoreleaseReturnValue方法時,runtime将這個傳回值object儲存在TLS中,然後直接傳回這個object(不調用autorelease);同時,在外部接收這個傳回值的objc_retainAutoreleasedReturnValue裡,發現TLS中正好存了這個對象,那麼直接傳回這個object(不調用retain)。
于是乎,調用方和被調方利用TLS做中轉,很有默契的免去了對傳回值的記憶體管理。
于是問題又來了,
隻能動用更進階的黑魔法。
__builtin_return_address
假如被調方和主調方隻有一邊是ARC環境編譯,(比如我們在ARC環境下用了非ARC編譯的第三方庫,或者反之),需要用到__builtin_return_address
這個内建函數原型是 char *__builtin_return_address(int level),
作用是得到函數的傳回位址,參數表示層數,如__builtin_return_address(0)表示目前函數體傳回位址,傳1是調用這個函數的外層函數的傳回值位址,以此類推。
- (int)foo {
NSLog(@"%p", __builtin_return_address(0)); // 根據這個位址能找到下面ret的位址
return 1;
}
// caller
int ret = [sark foo];
函數的傳回值位址,也就對應着調用者結束這次調用的位址(或者相差某個固定的偏移量,根據編譯器決定)
如果一個函數傳回前知道調用方是ARC還是非ARC,就有機會對于不同情況做不同的處理
##黑魔法之反查彙編指令
通過上面的__builtin_return_address加某些偏移量,被調方可以定位到主調方在傳回值後面的彙編指令:
于是乎,就有了下面的這個函數,入參是調用方__builtin_return_address傳入值
static bool callerAcceptsFastAutorelease(const void * const ra0) {
const uint8_t *ra1 = (const uint8_t *)ra0;
const uint16_t *ra2;
const uint32_t *ra4 = (const uint32_t *)ra1;
const void **sym;
// 48 89 c7 movq %rax,%rdi
// e8 callq symbol
if (*ra4 != 0xe8c78948) {
return false;
}
ra1 += (long)*(const int32_t *)(ra1 + 4) + 8l;
ra2 = (const uint16_t *)ra1;
// ff 25 jmpq *[email protected](%rip)
if (*ra2 != 0x25ff) {
return false;
}
ra1 += 6l + (long)*(const int32_t *)(ra1 + 2);
sym = (const void **)ra1;
if (*sym != objc_retainAutoreleasedReturnValue)
{
return false;
}
return true;
}
它檢驗了主調方在傳回值之後是否緊接着調用了objc_retainAutoreleasedReturnValue,如果是,就知道了外部是ARC環境,反之就走沒被優化的老邏輯。
其他Autorelease相關知識點
使用容器的block版本的枚舉器時,内部會自動添加一個AutoreleasePool:
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// 這裡被一個局部@autoreleasepool包圍着
}];
當然,在普通for循環和for in循環中沒有,是以,還是新版的block版本枚舉器更加友善。for循環中周遊産生大量autorelease變量時,就需要手加局部AutoreleasePool咯。
http協定中各個響應狀态200_301_404_500等傳回值含義快速一覽
一.定義 從HTTP的定義可以看出,HTTP協定是網際網路上進行資料通信的基礎協定,用來交換或傳輸超文本.超文本是一種結構化的文本,在包含文本的節點之間使用邏輯連結(也叫超連結). 二.概述 HTTP是 ...
GsonFormat根據傳回值json快速建構Model
Json是一個插件,我們隻需要在Android studio中進行安裝一下,即可使用. 根據平時的操作,根據浏覽器中傳回中的資料一行一行敲,其實這樣非常麻煩. 有一個簡單的方法,可以瞬間生成一個實體類 ...
c++特性:指向類成員的指針和非類型類模闆參數和函數指針傳回值 參數推導機制和關聯型别
一.c++允許定義指向類成員的指針,包括類函數成員指針和類資料成員指針 格式如下: class A { public: void func(){printf("This is a funct ...
Java反射機制二 擷取方法的傳回值或參數的泛型資訊
在使用反射機制時,我們經常需要知道方法的參數和傳回值類型,很簡單 ,下面上示例,示例中的兩個方法非常相似 package deadLockThread; import java.lang.refle ...
idea 快速生成傳回值快捷方式
idea java快速生成傳回值 ctrl+alt+V
關于java中ArrayList的快速失敗機制的漏洞——使用疊代器循環時删除倒數第二個元素不會報錯
一.問題描述 話不多說,先上代碼: public static void main(String[] args) throws InterruptedException { List
GetLastError()函數傳回值及含義
GetLastError傳回的值通過在api函數中調用SetLastError或SetLastErrorEx設定.函數并無必要設定上一次錯誤資訊,是以即使一次GetLastError調用傳回的是零值, ...
快速失敗機制--fail-fast
fail-fast 機制是Java集合(Collection)中的一種錯誤機制.當多個線程對同一個集合的内容進行操作時,就可能會産生fail-fast(快速失敗)事件.例如:當某一個線程A通過iter ...
Python第七天 函數 函數參數 函數裡的變量 函數傳回值 多類型傳值 函數遞歸調用 匿名函數 内置函數
Python第七天 函數 函數參數 函數裡的變量 函數傳回值 多類型傳值 函數遞歸調用 匿名函數 内置函數 目錄 Pycharm使用技巧(轉載) Python第一天 ...
随機推薦
CentOS 7 上編譯安裝MySQL 5.6.23
1.下載下傳源碼 wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.23.tar.gz 2.解壓 tar zxvf mysql-5.6 ...
vim指令---存閱
指令曆史 以:和/開頭的指令都有曆史紀錄,可以首先鍵入:或/然後按上下箭頭來選擇某個曆史指令. 啟動vim 在指令行視窗中輸入以下指令即可 vim 直接啟動vim vim filename 打開vim ...
IOS本地化應用
BK項目已完成7788,在項目的後期需要被翻譯成多國語言版.為了适應全球多個國家使用多個存儲. 應用本地化是分别對字元串.圖檔和 xib 或 storyboard 檔案本地化,而傳統的做法是對 xib ...
關于this指針了解
1. this指針的用處: 一個對象的this指針并不是對象本身的一部分,不會影響sizeof(對象)的結果.this作用域是在類内部,當在類的非靜态成員函數中通路類的非靜态成員的時候,編譯器會自動将 ...
Java程式基礎程式設計基礎
1.在螢幕上輸出"你好" //Programmer name Helloword.javapublic class Helloword { public static void m ...
QTableWidget class
Help on class QTableWidget in module PyQt5.QtWidgets: class QTableWidget(QTableView) | QTableWidge ...
C語言中的語句
• 表達式語句 表達式後加 ; 構成表達式語句. a = b+c; x+y i++ • 控制語句 完成一定的控制功能. if(...){...}else{...} ...
MySQL自定義函數和存儲過程的差別:
自定義函數和存儲過程的差別: 1)一般來說,存儲過程實作的功能要複雜一點,而函數的實作的功能針對性比較強.存儲過程,功能強大,可以執行包括修改表等一系列資料庫操作:使用者定義函數不能用于執行一組修改全局 ...
dart --- 更符合程式員程式設計習慣的javascript替代者
dart是google在2011年推出的一門語言,提供較為豐富的lib,并支援将代碼轉變為javascript,其demo code 和 demo app 也是以web前端代碼來展示的. 其語言特性較 ...