上圖打印的結果爲:
經過結果可知p1,p2,p3的對象地址都是同樣的,指針指向地址一樣也是同樣的,可是p1,p2,p3的指針地址不一樣。 經過上面打印能夠作以下猜想:alloc對對象進行了建立和內存分配,而init只是建立指針指向已建立好的內存地址。猜想對不對,咱們看下alloc和init的代碼執行過程。 咱們經過這樣設置斷點:
運行(剛開始將alloc斷點放過,等運行到咱們p1的alloc位置再打開),下一步,發現斷點進入到_objc_rootAlloc
還用一樣的方法設置_objc_rootAlloc斷點,發現進入下圖:
這方法咱們看到有兩個看得懂的方法_objc_rootAllocWithZone,以及objc_msgSend 咱們發現這種方法來看流程缺點很明顯,首先是慢,每進入一個方法都要打相對應的斷點。還有就是中間不少內容看不到,不適合。上面只是提供一個看內部實現的方法,最好的仍是看蘋果開源的代碼 咱們下載objc源碼,看到_objc_rootAlloc進入callAlloc,但實際運行的時候,咱們發現跟咱們上面直接斷點看到的是有出入的,它直接進的objc_alloc,後面補充:之因此沒有進alloc而是進了objc_alloc,查資料說的是在編譯期的時候若是符號綁定失敗了就會觸發一個這樣的修復操做,調用fixupMessageRef方法,明顯的能看到 if (msg->sel == SEL_alloc) , msg->imp = (IMP)&objc_alloc,將alloc方法和objc_alloc方法進行交換。(後面分析發現,咱們斷點打的alloc,並無打objc_alloc斷點,其實都是從objc_alloc開始,後面用消息發送方式去調用了alloc方法,來到咱們alloc斷點位置)
咱們繼續往下走,發現此時進入callAlloc直接進入objc_msgSend方法,調用的消息轉發,消息轉發去調用alloc方法
繼續往下走,斷點走到這了(其實先走的alloc方法後跳到下面方法)
繼續(注意上面圖中的callAlloc方法的傳參:false/checkNil/,true/allocWithZone/跟第一次objc_alloc方法中callAlloc方法傳參:true/checkNil/,false/allocWithZone/)經過語義可知:第一次傳參是須要檢查是否爲nil,沒有重寫allocWithZone,第二次傳參是不須要檢查是否爲nil,可是重寫了allocWithZone.
紅框字面意思快速跟慢速,能夠理解爲是否編譯優化(感受就是debug跟release不知道對不對)下一步,進入_objc_rootAllocWithZone
繼續下一步進入:_class_createInstanceFromZone(主角登場了)
爲啥說是主角呢?咱們先總覽整個方法
整個方法包含開闢內存,內存很isa綁定。繼續下一步,紅框內的方法是給size賦值,這個size咱們在整個方法裏看到是開闢內存空間大小的。咱們看下這個方法instanceSize看看size怎麼來的
看下這個方法,注意紅框,紅框內容是size不足16字節,就返回16字節,這就肯定內存空間的size最小是16字節。
咱們進入hasFastInstanceSize方法看看
其中__builtin_constant_p(extra)判斷extra是否爲編譯常數,整個方法查資料獲得的是這個方法判斷是否有緩存,具體怎麼判斷後面知道了再補充。 回到instanceSize方法,若是有緩存就直接返回緩存就會調用返回size,看下fastInstanceSizefan方法,注意紅框內容
紅框的方法是個算法,就是爲了保證返回的內存地址大小永遠是16字節的倍數。這就是傳說中的內存對齊(之因此內存對齊是爲了提升CPU讀取效率,這也是蘋果的規定)
回到_class_createInstanceFromZone打印返回的內存
發現返回內存是32字節(爲啥是32字節?由於有屬性這個自定義對象有兩個字符串屬性,一個int對象,應該是:8+8+8+4 = 28,取16的倍數爲32),繼續
obj = (id)calloc(1, size);這個方法爲開闢內存爲32字節的內存空間 咱們驗證下這個方法是不是建立了內存
執行這個方法前打印obj,結果:LGPerson
此時在打印obj爲內存地址
執行紅框後的方法,發現再打印obj就是咱們常打印的結果,因此說initInstanceIsa就是將內存地址跟LGPerson的isa指針進行綁定,此時obj的alloc完成。 總結下以下圖 alloc流程(咱們看到自定義對象在判斷是否存在自定義allocWithZoon是不存在的)
咱們看下若是是NSObject對象是什麼狀況 調試發如今判斷是否存在自定義allocWithZoon判斷是存在的
後面就同樣了 爲何自定義對象的自定義allocWithZoon是不存在的,而NSObject存在呢? 咱們看第一次調用的objc_alloc,其中checkNil爲true,allocWithZone爲false,由於第一次進來fastpath(!cls->ISA()->hasCustomAWZ())中的自定義對象cls尚未指針isa,因此爲false。走objc_msgSend,會再次調用callAlloc方法,可是此時的參數checkNil爲false,allocWithZone爲true。由於以前調用alloc方法,經過send_message方式調用了initialize類方法,自定義對象isa指針已經存在了(自定義類不存在自定義的allocWithZoon,但它父類NSObject是有的)。 可是NSObject類不一樣,由於他是系統類,在編譯的時候,它的isa指針已經存在了,因此爲true(後面感受不對) 補充:initialize方法會在第一次初始化該類以前調用。NSObject在運行的時候,別處已經初始化過了,因此在咱們對NSObject進行alloc時,initialize已經調用,isa指針已經存在 這也就是爲何自定義對象會走兩邊callAlloc,而NSObject只走一遍的緣由。 補充:經過上面的解釋,能夠肯定,相同類屢次alloc,第一次fastpath(!cls->ISA()->hasCustomAWZ())爲false,但以後都應該爲true,也就是不在走_objc_rootAlloc方法。以後的驗證也證實這樣的猜想是對的 上面就是對OC對象alloc的理解,若是理解有什麼問題,望指正,謝謝!算法