Autorelease返回值的快速釋放機制

来源:http://www.cnblogs.com/rainySue/archive/2016/08/15/Autorelease-fan-hui-zhi-de-kuai-su-shi-fang-ji-zhi.html
-Advertisement-
Play Games

+ (instancetype)createSark { return [self new];}// callerSark *sark = [Sark createSark];編譯器改寫成了形如下麵的代碼:+ (instancetype)createSark { id tmp = [self new... ...


+ (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 *symbol@DYLDMAGIC(%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咯。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • PFold.js是一款摺疊紙片插件,支持定義摺疊紙牌數量、摺疊動畫效果、摺疊方向,而且還支持摺疊結束後回調方法。 線上實例 使用方法 複製 複製 參數詳解 方法Method 下載 ...
  • CSS製作三角形和按鈕 用上一篇博文中關於邊框樣式的知識點,能製作出三角形和按鈕。 我先說如何製作三角形吧,相信大家在平時逛網站的時候都會看到一些導航欄中的三角形吧,比如說: 網易首頁的頭部菜單欄中,也會有這樣的三角形 當滑鼠經過時,三角形會垂直翻轉,如下 現在我分享製作三角形的做法,主要是利用邊框 ...
  • 對AngularJS的作用域做深入剖析,該隨筆主要分為兩大板塊:JavaScript原型鏈、AngularJS作用域。 ...
  • 對於CSS的學習到此就告一段落了,其中自己感覺在CSS的學習中最有效的方法還是去進行大量的案例仿寫,這樣我們可以學習別的人是怎樣佈局的,不會不要緊,可以多去學習借鑒一下別人的經驗啊。 這兩天又接觸了onmouseover事件和onmouseout事件,一直以為它們只是簡單的分別實現滑鼠指針移動到元素 ...
  • 寫在前面本人才是開始學習前端的菜鳥有很多不懂的忘大神指點 html全名Hyper TextMarkup Language 下麵說說常用的到的html的元素標簽 h1 h2 h3 h4 h5 h6 6級的標題標簽 ul 無序列表標簽 子元素用 li ol 有序列表標簽 子元素用 li a 超鏈接標簽 ...
  • 1. 說明 管道用來轉換模板顯示的內容,應用程式中經常出現獲取數據,轉換數據,顯示數據的邏輯。管道就是用來在轉換數據階段起作用的。主要存在兩種類型的管道,pure pipe和impure pipe 2. Pure Pipe Pure Pipe,stateless,關註於純粹對象的變更,檢測到輸入值發 ...
  • 理解Method Swizzling是學習runtime機制的一個很好的機會。在此不多做整理,僅翻譯由Mattt Thompson發表於nshipster的Method Swizzling一文。 Method Swizzling是改變一個selector的實際實現的技術。通過這一技術,我們可以在運行 ...
  • 1、TableView頭視圖不隨視圖移動,頭視圖出現錯位 錯誤原因:tableView的 UITableViewStyle 沒有明確的聲明 解決方法:在tableView聲明的時候明確為 UITableViewStyleGrouped 2、分組表視圖頂部空白高度調整 實現方式: 方式一(推薦使用): ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...