【iOS】alloc init new底層原理

目錄

前言

alloc

alloc核心操作

cls->instanceSize(extraBytes)

calloc

obj->initInstanceIsa

init

類方法:

實例方法:

new


前言

筆者最近在進行對OC語言源碼的學習,學習源碼的過程中經常會出現一些從來沒有遇見過的函數,因此很難把整個過程理解清楚,這篇博客先簡單梳理一下我現在理解的 alloc & init & new 的實現過程以及內存對齊原理

alloc

首先從main函數中找到WGPerson類的alloc方法的實現:

在這個方法中,調用了_objc_rootAlloc,跳轉到該函數的實現:

這個方法中又調用了callAlloc函數,同樣跳轉到該函數的實現:

這個函數是runtime中分配對象的核心方法之一,用于決定走哪條路徑調用alloc或allocWithZone:

static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)

這兩行是這個函數的定義部分,static說明這個函數只能在當前文件中使用,ALWAYS_INLINE表示這個函數應盡量內聯,提高性能。

函數有三個參數,cls表示要分配內存的類,checkNil是一個bool變量,用于表明是否需要檢查cls是否為nil,allocWithZone表示是否使用allocWithZone:方法。

函數內部實現里有三個判斷,第一個判斷是類是否為nil

#if __OBJC2__if (slowpath(checkNil && !cls)) return nil;

__OBJC2__表示僅在OC2.0環境下有效,<!--slowpath用于分支預測優化,提示這個條件大概率為假-->,checkNil && !cls 表示如果要求檢查且cls是nil,就直接返回nil。

?if (fastpath(!cls->ISA()->hasCustomAWZ())) {return _objc_rootAllocWithZone(cls, nil);}
#endif

<!--fastpath與slowpath相對,也是用于分支預測優化的,它提示這個條件大概率為真。-->cls->ISA()用于獲取類的元類,hasCustomAWZ()用于判斷類是否重寫了allocWithZone:這個方法,

進入條件語句后,_objc_rootAllocWithZone(cls, nil)是調用runtime的根分配方法 ,分配對象。

如果沒有進入這條快路徑,就只能走慢路徑,發消息調用alloc/allocWithZone:

if (allocWithZone) {return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);}

objc_msgSend:是runtime的消息發送函數,cls和@selector(allocWithZone:)是這個函數的兩個參數,這條語句前面的部分((id(*)(id, SEL, struct _NSZone *))是在對objc_msgSend:函數進行類型轉換,把函數轉換成了返回一個id,接收兩個參數:id,SEL的函數,這樣來正確調用alloc方法。

這條語句就相當于給類對象cls發送alloc消息,從而創建一個該類的實例對象。

最后一種情況是當allocWithZone為假時,正常調用 alloc走常規路徑,objc_msgSend: 發送 alloc消息,等效于[cls alloc]

在這里我們對自定義類進行觀察,會在這幾個分支中走到_objc_rootAllocWithZone,接著我們跳轉到_objc_rootAllocWithZone的實現。

再繼續跳轉到_class_createInstanceFromZone的源碼實現,這個部分是alloc源碼的核心操作,實現主要分為三個部分:

  • cls->instanceSize:計算需要開辟的<!--內存空間大小-->

  • calloc:<!--申請內存-->,返回地址指針

  • obj->initInstanceIsa:將類與isa關聯

static ALWAYS_INLINE id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,int construct_flags = OBJECT_CONSTRUCT_NONE,bool cxxConstruct = true,size_t *outAllocatedSize = nil)
{ASSERT(cls->isRealized());
?// Read class's info bits all at once for performancebool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();bool hasCxxDtor = cls->hasCxxDtor();bool fast = cls->canAllocNonpointer();size_t size;
?size = cls->instanceSize(extraBytes);if (outAllocatedSize) *outAllocatedSize = size;
?id obj;if (zone) {obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);} else {obj = (id)calloc(1, size);}if (slowpath(!obj)) {if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {return _objc_callBadAllocHandler(cls);}return nil;}
?if (!zone && fast) {obj->initInstanceIsa(cls, hasCxxDtor);} else {// Use raw pointer isa on the assumption that they might be// doing something weird with the zone or RR.obj->initIsa(cls);}
?if (fastpath(!hasCxxCtor)) {return obj;}
?construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;return object_cxxConstructFromClass(obj, cls, construct_flags);
}

alloc核心操作

cls->instanceSize(extraBytes)

instanceSize(extraBytes)的實現如下:

instanceSize的調用過程如下:

這里自定義類最終走到fastInstanceSize

在fastInstanceSize中,最終調用的是align16這個函數,在834源碼中使用是align16這個函數,在最新版xcode中會報紅。

但是可以看到在906源碼中其實也調用的是align16這個函數。這個函數的實現是一個16字節對齊算法

這段算法的過程就是將原始的內存 與size_t(15)相加,得到一個數,將 size_t(15) 即 15進行~(取反)操作,再將 這個數 與 15的取反結果 進行 &(與)操作,最后的結果為 16的倍數,即內存的大小是以16的倍數增加的

原理是因為內存必須比數據大,內存對齊的結果只能大于實際數據大小,而不能比它小。將數字加15,使數字大于等于比數據大小要大的最小的那個16的倍數,在和末四位為0的數字進行與操作,抹去后四位,去掉余數,變成16的倍數。

為什么需要內存對齊?

通常內存是由一個個字節組成的,cpu在存取數據時,并不是以字節為單位存儲,而是以為單位存取,塊的大小為內存存取力度。頻繁存取字節未對齊的數據,會極大降低cpu的性能,所以可以通過減少存取次數降低cpu的開銷

16字節對齊,是由于在一個對象中,第一個屬性isa8字節,當然一個對象肯定還有其他屬性,當無屬性時,會預留8字節,即16字節對齊,如果不預留,相當于這個對象的isa和其他對象的isa緊挨著,容易造成訪問混亂

16字節對齊后,可以加快CPU讀取速度,同時使訪問更安全,不會產生訪問混亂的情況

calloc

calloc函數用于申請內存并返回地址指針

obj = (id)calloc(1, size);

這一行代碼就是在用計算出來的size獲取地址指針obj,此時地址還沒有與傳入的cls進行關聯。

obj->initInstanceIsa

這一步是在將類與isa關聯。內存申請好后,將傳入的類與已經申請好的內存進行關聯,而關聯的方式就是isa指針。關聯的流程如下:

在執行完initInstanceIsa后,內存便與類關聯了起來。

綜上,alloc的核心操作就是三步:計算內存,申請內存,內存與類關聯。

init

init有兩種,一種是類的init,一種是對象的。

類方法:

+ (id)init {return (id)self;
}

這里的init是一個構造方法 ,是通過工廠設計(工廠方法模式),主要是用于給用戶提供構造方法入口。這里能使用id強轉的原因,主要還是因為 內存字節對齊后,可以使用類型強轉為你所需的類型

實例方法:

init實例方法會跳轉到_objc_rootInit方法,來看看它的實現

可以發現,函數返回的是傳入的self本身。

new

除了alloc與init,初始化還可以使用new方法

new其實就是調用了callAlloc函數(即alloc中分析的函數)以及init函數,因此就相當于[[ alloc] init]。

但是如果重寫了init方法做一些自定義操作,這時會在這個方法中調用[super init],這時不建議使用new進行初始化。

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

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

相關文章

QT窗口相關控件及其屬性

widget&#xff0c;PushButton&#xff0c;lineEdit等都是基于QWidget延展出來的 并不是完整的窗口&#xff0c;而是作為窗口的一部分 真正的窗口是QMainWindow 菜單欄 Qt中的菜單欄是通過QMenuBar這個類來實現的&#xff0c;一個主窗口最多只有一個菜單欄&#xff0c;位于主…

day47—雙指針-平方數之和(LeetCode-633)

題目描述 給定一個非負整數 c &#xff0c;你要判斷是否存在兩個整數 a 和 b&#xff0c;使得 a^2 b^2 c 。 示例 1&#xff1a; 輸入&#xff1a;c 5 輸出&#xff1a;true 解釋&#xff1a;1 * 1 2 * 2 5示例 2&#xff1a; 輸入&#xff1a;c 3 輸出&#xff1a;f…

藍橋杯 20. 壓縮變換

壓縮變換 原題目鏈接 題目描述 小明最近在研究壓縮算法。他知道&#xff0c;壓縮時如果能夠使數值很小&#xff0c;就能通過熵編碼得到較高的壓縮比。然而&#xff0c;要使數值變小是一個挑戰。 最近&#xff0c;小明需要壓縮一些正整數序列&#xff0c;這些序列的特點是&a…

element-ui多個form同時驗證,以及動態循環表單注意事項

多個form同時驗證&#xff1a; validateForm(refs) {if (!refs) {return false}return new Promise((resolve, reject) > {refs.validate().then((valid) > {resolve(valid)}).catch((val) > {resolve(false)})}) }, async handleConfirm() {Promise.all([this.valid…

Spring Boot中自定義404異常處理問題學習筆記

1. 問題背景 在Spring Boot項目中&#xff0c;需要手動返回404異常給前端。為此&#xff0c;我創建了一個自定義的404異常類UnauthorizedAccessException&#xff0c;并在全局異常處理器GlobalExceptionHandler中處理該異常。然而&#xff0c;在使用Postman測試時&#xff0c;…

你學會了些什么220622?--搭建UI自動化

jenkins訪問地址&#xff1a;http://192.168.82.129:8080/ 賬號密碼&#xff1a;admin/a123456a ***** 什么是UI自動化** 使用工具或者腳本對需要測試的軟件的前端界面在預設的條件下&#xff0c;在已有的測試數據下運行系統或者應用程序&#xff0c;并獲取其前端頁面UI顯示的…

【2025計算機網絡-面試常問】http和https區別是什么,http的內容有哪些,https用的是對稱加密還是非對稱加密,流程是怎么樣的

HTTP與HTTPS全面對比及HTTPS加密流程詳解 一、HTTP與HTTPS核心區別 特性HTTPHTTPS協議基礎明文傳輸HTTP SSL/TLS加密層默認端口80443加密方式無加密混合加密&#xff08;非對稱對稱&#xff09;證書要求不需要需要CA頒發的數字證書安全性易被竊聽、篡改、冒充防竊聽、防篡改…

JavaFX 第一篇 Hello World

1、簡介 JavaFX 是一個用于構建客戶端應用程序的 Java 庫&#xff0c;作為 Java 標準庫的一部分&#xff08;JDK 8 到 10&#xff09;&#xff0c;從 JDK 11 開始&#xff0c;JavaFX 將以獨立模塊發布&#xff0c;將不再包含在 JDK標準庫中&#xff0c;他是 Java 應用程序開發的…

SQL實戰:02之連續數問題求解

文章目錄 概述題目:體育館的人流量題解步驟一&#xff1a;構造出一個連續序列步驟二&#xff1a;找出符合條件的組的序號步驟三&#xff1a;fetch結果&#xff0c;使用內連接過濾出符合條件的記錄。完整SQL 題目二&#xff1a;連續出現的數字題解步驟一&#xff1a;分區并構建連…

STM32 的 GPIO和中斷

GPIO的簡單介紹 內部結構 施密特觸發器&#xff08;TTL肖特基觸發器&#xff09; 的工作原理&#xff1a; 施密特觸發電路&#xff08;簡稱&#xff09;是一種波形整形電路&#xff0c;當任何波形的信號進入電路時&#xff0c;輸出在正、負飽和之間跳動&#xff0c;產生方波或…

Server - 優雅的配置服務器 Bash 環境(.bashrc)

歡迎關注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/147335592 免責聲明&#xff1a;本文來源于個人知識與公開資料&#xff0c;僅用于學術交流&#xff0c;歡迎討論&#xff0c;不支持轉載。 登錄服…

使用PyTorch實現圖像增廣與模型訓練實戰

本文通過完整代碼示例演示如何利用PyTorch和torchvision實現常用圖像增廣方法&#xff0c;并在CIFAR-10數據集上訓練ResNet-18模型。我們將從基礎圖像變換到復雜數據增強策略逐步講解&#xff0c;最終實現一個完整的訓練流程。 一、圖像增廣基礎操作 1.1 準備工作 #matplotli…

解決Mac 安裝 PyICU 依賴失敗

失敗日志&#xff1a; 解決辦法 1、使用 homebrew 安裝相關依賴 brew install icu4c 安裝完成后&#xff0c;設置環境變量 echo export PATH"/opt/homebrew/opt/icu4c77/bin:$PATH" >> ~/.zshrcecho export PATH"/opt/homebrew/opt/icu4c77/sbin:$PATH…

Springboot后端查詢參數接收

1.實現方式 假設前端發送的接口&#xff1a; /users?nameJohn&age30 后端怎么接收里面的name和age呢&#xff1f;以及再發別的參數后端怎么接收呢&#xff1f; 1.比較簡單的方式 當控制器方法的參數類型是簡單類型&#xff08;如 String、Integer、Long 等&#xff09…

桌面應用中VUE使用新瀏覽器窗口打開頁面

1、瀏覽器應用忽略此方式&#xff0c;可任意方式打開。針對桌面應用設置 newWindowClick(){try {this.fileUrl "";this.params.year ""this.params.date ""axios({method: post,url: /url/pdf/preview,data: this.params,}).then(res> {t…

華為手機怎么進行音頻降噪?音頻降噪技巧分享:提升聽覺體驗

在當今數字化時代&#xff0c;音頻質量對于提升用戶體驗至關重要&#xff0c;無論是在通話、視頻錄制還是音頻文件播放中&#xff0c;清晰的音頻都能帶來更佳的聽覺享受。 而華為手機憑借其強大的音頻處理技術&#xff0c;為用戶提供了多種音頻降噪功能&#xff0c;幫助用戶在…

【數據可視化-22】脫發因素探索的可視化分析

?? 博主簡介:曾任某智慧城市類企業算法總監,目前在美國市場的物流公司從事高級算法工程師一職,深耕人工智能領域,精通python數據挖掘、可視化、機器學習等,發表過AI相關的專利并多次在AI類比賽中獲獎。CSDN人工智能領域的優質創作者,提供AI相關的技術咨詢、項目開發和個…

青少年編程與數學 02-018 C++數據結構與算法 06課題、樹

青少年編程與數學 02-018 C數據結構與算法 06課題、樹 一、樹(Tree)1. 樹的定義2. 樹的基本術語3. 常見的樹類型4. 樹的主要操作5. 樹的應用 二、二叉樹(Binary Tree)1. 二叉樹的定義2. 二叉樹的基本術語3. 二叉樹的常見類型4. 二叉樹的主要操作5. 二叉樹的實現代碼說明輸出示例…

【論文閱讀】Visual Instruction Tuning

文章目錄 導言1、論文簡介2、論文主要方法3、論文針對的問題4、論文創新點總結 導言 本論文介紹了一個新興的多模態模型——LLaVA&#xff08;Large Language and Vision Assistant&#xff09;&#xff0c;旨在通過指令調優提升大型語言模型&#xff08;LLM&#xff09;在視覺…

【學習筆記】Cadence電子設計全流程(三)Capture CIS 原理圖繪制(下)

【學習筆記】Cadence電子設計全流程&#xff08;三&#xff09;Capture CIS 原理圖繪制&#xff08;下&#xff09; 3.16 原理圖中元件的編輯與更新3.17 原理圖元件跳轉與查找3.18 原理圖常見錯誤設置于編譯檢查3.19 低版本原理圖文件輸出3.20 原理圖文件的鎖定與解鎖3.21 Orca…