alloc&init&new源碼分析

本文只做個人筆記使用旗国,引用部分會在文末著名來源

alloc+inti整體流程:


alloc+init源碼流程

alloc核心三步:
1.先計算出需要的內(nèi)存大小空間;
2.向系統(tǒng)申請開辟內(nèi)存距淫,返回地址指針袖扛;
3.將cls類與obj指針關(guān)聯(lián);

instanceSize的源碼中實現(xiàn)內(nèi)存大小

size_t instanceSize(size_t extraBytes) const {
   //編譯器快速計算內(nèi)存大小
   if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
       return cache.fastInstanceSize(extraBytes);
   }
   
   // 計算類中所有屬性的大小 + 額外的字節(jié)數(shù)0
   size_t size = alignedInstanceSize() + extraBytes;
   // CF requires all objects be at least 16 bytes.
   //如果size 小于 16弯蚜,最小取16
   if (size < 16) size = 16;
   return size;
}

通過斷點調(diào)試孔轴,會執(zhí)行cache.fastInstanceSize方法,快速計算內(nèi)存大小

fastInstanceSize源碼中碎捺,會執(zhí)行到align16

size_t fastInstanceSize(size_t extra) const
{
    ASSERT(hasFastInstanceSize(extra));

    //Gcc的內(nèi)建函數(shù) __builtin_constant_p 用于判斷一個值是否為編譯時常數(shù)路鹰,如果參數(shù)EXP 的值是常數(shù),函數(shù)返回 1收厨,否則返回 0
    if (__builtin_constant_p(extra) && extra == 0) {
        return _flags & FAST_CACHE_ALLOC_MASK16;
    } else {
        size_t size = _flags & FAST_CACHE_ALLOC_MASK;
        // remove the FAST_CACHE_ALLOC_DELTA16 that was added
        // by setFastInstanceSize
        //刪除由setFastInstanceSize添加的FAST_CACHE_ALLOC_DELTA16 8個字節(jié)
        return align16(size + extra - FAST_CACHE_ALLOC_DELTA16);
    }
}

align16的源碼中晋柱,這個方法是16字節(jié)對齊算法

//16字節(jié)對齊算法
static inline size_t align16(size_t x) {
    return (x + size_t(15)) & ~size_t(15);
}

內(nèi)存對齊原則:
1:數(shù)據(jù)成員對?規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第
?個數(shù)據(jù)成員放在offset為0的地?诵叁,以后每個數(shù)據(jù)成員存儲的起始位置要從該成員??或者成員的?成員??(只要該成員有?成員雁竞,?如說是數(shù)組,結(jié)構(gòu)體等)的整數(shù)倍開始(?如int為4字節(jié),則要從4的整數(shù)倍地址開始存儲黎休。 min(當前開始的位置m n) m = 9 n = 4 9 10 11 12
2:結(jié)構(gòu)體作為成員:如果?個結(jié)構(gòu)?有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最?元素??的整數(shù)倍地址開始存儲.(struct a?存有struct b,b?有char,int ,double等元素,那b應該從8的整數(shù)倍開始存儲.)
3:收尾?作:結(jié)構(gòu)體的總??,也就是sizeof的結(jié)果,必須是其內(nèi)部最?
成員的整數(shù)倍浓领,不?的要補?玉凯。

為什么需要16字節(jié)對齊

需要字節(jié)對齊的原因,有以下幾點:

通常內(nèi)存是由一個個字節(jié)組成的联贩,cpu在存取數(shù)據(jù)時漫仆,并不是以字節(jié)為單位存儲,而是以塊為單位存取泪幌,塊的大小為內(nèi)存存取力度盲厌。頻繁存取字節(jié)未對齊的數(shù)據(jù),會極大降低cpu的性能祸泪,所以可以通過減少存取次數(shù)來降低cpu的開銷
16字節(jié)對齊吗浩,是由于在一個對象中,第一個屬性isa占8字節(jié)没隘,當然一個對象肯定還有其他屬性懂扼,當無屬性時,會預留8字節(jié)右蒲,即16字節(jié)對齊阀湿,如果不預留,相當于這個對象的isa和其他對象的isa緊挨著瑰妄,容易造成訪問混亂
16字節(jié)對齊后陷嘴,可以加快CPU讀取速度,同時使訪問更安全间坐,不會產(chǎn)生訪問混亂的情況
字節(jié)對齊-總結(jié)

在字節(jié)對齊算法中灾挨,對齊的主要是對象,而對象的本質(zhì)則是一個 struct objc_object的結(jié)構(gòu)體竹宋,
結(jié)構(gòu)體在內(nèi)存中是連續(xù)存放的劳澄,所以可以利用這點對結(jié)構(gòu)體進行強轉(zhuǎn)。
蘋果早期是8字節(jié)對齊蜈七,現(xiàn)在是16字節(jié)對齊浴骂。

總結(jié):
1.通過對alloc源碼的分析可以得知alloc的只要目的就是開辟內(nèi)存,而且開辟的內(nèi)存需要使用16字節(jié)對齊的算法宪潮,現(xiàn)在開辟的內(nèi)存基本上都是16的整數(shù)倍溯警;
2.開辟內(nèi)存的核心步驟有三步:計算內(nèi)存大小-申請內(nèi)存-將isa與cls關(guān)聯(lián)

init源碼探索
類方法init

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

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

實例方法init

- (id) init {
    return _objc_rootInit(self);
}

進入_objc_rootInit源碼

id _objc_rootInit(id obj)
{
    // In practice, it will be hard to rely on this function.
    // Many classes do not properly chain -init calls.
    return obj;
}

返回的是傳入的 self本身

new源碼
一般在開發(fā)中尽棕,初始化除了init喳挑,還可以使用new,兩者本質(zhì)上并沒有什么區(qū)別,以下是objc中new的源碼實現(xiàn)伊诵,通過源碼可以得知单绑,new函數(shù)中直接調(diào)用了callAlloc函數(shù)(即alloc中分析的函數(shù)),且調(diào)用了init函數(shù)曹宴,所以可以得出new 其實就等價于 [alloc init]的結(jié)論 .

+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}

一般開發(fā)中并不建議使用new搂橙,主要是因為有時會重寫init方法做一些自定義的操作,例如 initWithXXX笛坦,會在這個方法中調(diào)用[super init]区转,用new初始化可能會無法走到自定義的initWithXXX部分。

參考鏈接:http://www.reibang.com/p/b72018e88a97

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末版扩,一起剝皮案震驚了整個濱河市废离,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌礁芦,老刑警劉巖蜻韭,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異柿扣,居然都是意外死亡湘捎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門窄刘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人舷胜,你說我怎么就攤上這事娩践。” “怎么了烹骨?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵翻伺,是天一觀的道長。 經(jīng)常有香客問我沮焕,道長吨岭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任峦树,我火速辦了婚禮辣辫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘魁巩。我一直安慰自己急灭,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布谷遂。 她就那樣靜靜地躺著葬馋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上畴嘶,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天蛋逾,我揣著相機與錄音,去河邊找鬼窗悯。 笑死区匣,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蟀瞧。 我是一名探鬼主播沉颂,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼悦污!你這毒婦竟也來了铸屉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤切端,失蹤者是張志新(化名)和其女友劉穎彻坛,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踏枣,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡昌屉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了茵瀑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片间驮。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖马昨,靈堂內(nèi)的尸體忽然破棺而出竞帽,到底是詐尸還是另有隱情,我是刑警寧澤鸿捧,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布屹篓,位于F島的核電站,受9級特大地震影響匙奴,放射性物質(zhì)發(fā)生泄漏堆巧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一泼菌、第九天 我趴在偏房一處隱蔽的房頂上張望谍肤。 院中可真熱鬧,春花似錦哗伯、人聲如沸谣沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乳附。三九已至内地,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赋除,已是汗流浹背阱缓。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留举农,地道東北人荆针。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像颁糟,于是被迫代替她去往敵國和親航背。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354