iOS底層之內(nèi)存對(duì)齊

一朱浴、什么是內(nèi)存對(duì)齊?

內(nèi)存對(duì)齊是一種在計(jì)算機(jī)內(nèi)存中排列數(shù)據(jù)(表現(xiàn)為變量的地址)抗蠢、訪問數(shù)據(jù)(表現(xiàn)為CPU讀取數(shù)據(jù))的一種方式犬庇。

它包含了兩種相互獨(dú)立又相互關(guān)聯(lián)的部分:基本數(shù)據(jù)對(duì)齊結(jié)構(gòu)體數(shù)據(jù)對(duì)齊 俯渤。

二呆细、為什么要進(jìn)行內(nèi)存對(duì)齊?

1、平臺(tái)原因(移植原因):不是所有的硬件平臺(tái)都能訪問任意地址上的任意數(shù)據(jù)的絮爷;某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù)趴酣,否則拋出硬件異常。
2坑夯、性能原因:數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊岖寞。原因在于,為了訪問未對(duì)齊的內(nèi)存柜蜈,處理器需要作兩次內(nèi)存訪問仗谆;而對(duì)齊的內(nèi)存訪問僅需要一次訪問。

說的通俗點(diǎn)就是方便讀取淑履,速度快隶垮。

三、內(nèi)存對(duì)齊原則:

1秘噪、數(shù)據(jù)成員對(duì)?規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員狸吞,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員存儲(chǔ)的起始位置要從該成員大小或者成員的子成員大小(只要該成員有子成員指煎,比如說是數(shù)組蹋偏,結(jié)構(gòu)體等)的整數(shù)倍開始(比如int為4字節(jié),則要從4的整數(shù)倍地址開始存儲(chǔ))。下面咱們用(m, n)來理解一下至壤,其中m為內(nèi)存的起始位置威始,n為當(dāng)前成員的內(nèi)存大小m像街,n一定要滿足m%n==0字逗。

2、結(jié)構(gòu)體作為成員:如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員宅广,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小整數(shù)倍地址開始存儲(chǔ)(struct a里存有struct b葫掉,b里有char、int 跟狱、double等元素,那b應(yīng)該從8的整數(shù)倍開始存儲(chǔ)俭厚。)

3、收尾工作:結(jié)構(gòu)體的總大小驶臊,也就是sizeof的結(jié)果挪挤,必須是其內(nèi)部最大成員整數(shù)倍不足的要補(bǔ)?关翎。

各位同學(xué)扛门,能理解上面這些原則嗎,反正光看文字我是理解不了纵寝,沒關(guān)系论寨,咱們是程序員,咱們可以用代碼來解釋。

四葬凳、數(shù)據(jù)成員結(jié)構(gòu)體內(nèi)存分析

struct Struct1 {
    double a;   // 8
    char b;     // 1
    int c;      // 4
    short d;    // 2
}struct1;

struct Struct2 {
    double a;   //8
    int b;      //4
    char c;     //1
    short d;    //2
}struct2;
NSLog(@"結(jié)果為:%lu-%lu",sizeof(struct1),sizeof(struct2));

咱們來看下打印結(jié)果

 結(jié)果為:24-16

為什么會(huì)出現(xiàn)不同的結(jié)果呢绰垂,咱們來分析一下,不過在分析代碼之前呢咱們先看下各個(gè)類型的內(nèi)存大小

數(shù)據(jù)類型內(nèi)存大小表

下面咱們來分析一下Struct1的結(jié)果:

  • 首先Struct1中以double開始火焰,在內(nèi)存中的地址是0~7劲装。
  • 接下來是charchar占用內(nèi)存大小為1字節(jié)昌简,此時(shí)在內(nèi)存中的起始地址8占业,此時(shí)8%1==0表示可以從此位置開始存放char,在內(nèi)存中的地址是8纯赎。
  • 然后是int纺酸,int占用內(nèi)存大小為4字節(jié),此時(shí)在內(nèi)存中的起始位置9址否,但是現(xiàn)在9%4 != 0餐蔬,所以此時(shí)只能向后移,找到一個(gè)能被4整除的數(shù)佑附,下一個(gè)能被4整除的數(shù)是12樊诺,所以此時(shí)int的起始位置為12,長度為4字節(jié)音同,在內(nèi)存中的地址是12~15词爬。
  • 最后是shortshort占用內(nèi)存2字節(jié)权均,此時(shí)內(nèi)存中的起始位置16顿膨,16%2==0成立,所以short在內(nèi)存中的起始位置是16叽赊,長度為2恋沃,在內(nèi)存中的地址是16~17
    由上述結(jié)果可得Struct1在內(nèi)存中占用18個(gè)字節(jié)必指,根據(jù)內(nèi)存對(duì)齊第三條原則囊咏,Struct1內(nèi)部最大成員為double8字節(jié),所以Struct1最終占用的內(nèi)存大小為24字節(jié)塔橡。由此可以得出下圖:
    Struct1內(nèi)存分布圖

同理梅割,我們再來分析一下Struct2的結(jié)果:

  • 首先Struct2中以double開始,在內(nèi)存中的地址是0~7葛家。
  • 然后是int户辞,int占用內(nèi)存大小為4字節(jié),此時(shí)在內(nèi)存中的起始位置8癞谒,8%4 == 0等式成立底燎,所以此時(shí)int的起始位置為8刃榨,長度為4字節(jié),在內(nèi)存中的地址是8~11书蚪。
  • 接下來是charchar占用內(nèi)存大小為1字節(jié)迅栅,此時(shí)在內(nèi)存中的起始地址12殊校,此時(shí)12%1==0等式成立表示可以從此位置開始存放char,在內(nèi)存中的地址是12读存。
  • 最后是short为流,short占用內(nèi)存2字節(jié),此時(shí)內(nèi)存中的起始位置13让簿,13%2==0等式不成立敬察,需要向后移,找到一個(gè)能被2整除的數(shù)尔当,所以short在內(nèi)存中的起始位置是14莲祸,長度為2,在內(nèi)存中的地址是14~15椭迎。
    有上述結(jié)果可得Struct2在內(nèi)存中占用16個(gè)字節(jié)锐帜,根據(jù)內(nèi)存對(duì)齊原則第三條,Struct2內(nèi)部最大成員為double8字節(jié)畜号,所以Struct2最終占用的內(nèi)存大小為16字節(jié)缴阎。由此可得出下圖:
    Struct2內(nèi)存分布圖

這就是Struct1Struct2結(jié)果不同的原因。
由此我們可以得出結(jié)論:結(jié)構(gòu)體所占內(nèi)存大小與結(jié)構(gòu)體內(nèi)部的成員變量的順序有關(guān)简软。

五蛮拔、嵌套結(jié)構(gòu)體內(nèi)存分析

struct Struct3 {
    double a;              //8
    char b;                //4
    struct Struct1 c;      //24
    short d;               //2
}struct3;

struct Struct4 {
    double a;              //8
    char b;                //1
    short c;               //2
    struct Struct2 d;      //16
}struct4;
NSLog(@"結(jié)果為:%lu-%lu",sizeof(struct3),sizeof(struct4));

咱們來看下打印結(jié)果

結(jié)果為:48-32

我們來分析下Struct3的結(jié)果:

  • 首先Struct3中以double開始,在內(nèi)存中的地址是0~7痹升。
  • 接下來是char建炫,char占用內(nèi)存大小為1字節(jié),此時(shí)在內(nèi)存中的起始地址8疼蛾,此時(shí)8%1==0等式成立表示可以從此位置開始存放char踱卵,在內(nèi)存中的地址是8,在內(nèi)存中的地址是8据过。
  • 然后是結(jié)構(gòu)體Struct1惋砂,由上面的結(jié)論得知Struct1的大小為24字節(jié),此時(shí)在內(nèi)存中的起始地址9绳锅,根據(jù)內(nèi)存對(duì)齊原則第二條得知需從其內(nèi)部最大元素大小整數(shù)倍地址開始存儲(chǔ)西饵,Struct1中最大的為double8字節(jié)9%8 == 0不成立鳞芙,所以取最近的一個(gè)能被8整除的數(shù)為16眷柔,所以Struct1在內(nèi)存中的起始位置為16期虾,長度為24,在內(nèi)存中的地址是16~39驯嘱。
  • 最后是short镶苞,short占用內(nèi)存2字節(jié),此時(shí)內(nèi)存中的起始位置40鞠评,40%2==0等式成立茂蚓,起始位置是40,長度為2剃幌,在內(nèi)存中的地址是40~41聋涨。
    有上述結(jié)果可得Struct3在內(nèi)存中占用42個(gè)字節(jié),根據(jù)內(nèi)存對(duì)齊原則负乡,Struct3內(nèi)部包括子成員Struct1內(nèi)部最大成員為double8字節(jié)牍白,所以Struct3最終占用的內(nèi)存大小為48字節(jié)。由此可得出下圖:
    Struct3內(nèi)存分布圖

我們來分析下Struct4的結(jié)果:

  • 首先Struct4中以double開始抖棘,在內(nèi)存中的地址是0~7茂腥。
  • 接下來是charchar占用內(nèi)存大小為1字節(jié)切省,此時(shí)在內(nèi)存中的起始地址8础芍,此時(shí)8%1==0等式成立表示可以從此位置開始存放char,在內(nèi)存中的地址是8数尿,在內(nèi)存中的地址是8仑性。
  • 然后是shortshort占用內(nèi)存2字節(jié)右蹦,此時(shí)內(nèi)存中的起始位置9诊杆,9%2==0等式不成立,其后能被2整除的數(shù)為10何陆,那么起始位置是10晨汹,長度為2,在內(nèi)存中的地址是10~11贷盲。
  • 最后是結(jié)構(gòu)體Struct2淘这,由上面的結(jié)論得知Struct2的大小為16字節(jié),此時(shí)在內(nèi)存中的起始地址12巩剖,根據(jù)內(nèi)存對(duì)齊原則第二條得知需從其內(nèi)部最大元素大小整數(shù)倍地址開始存儲(chǔ)铝穷,Struct2中最大的為double8字節(jié)12%8 == 0不成立佳魔,所以取最近的一個(gè)能被8整除的數(shù)為16曙聂,所以Struct2在內(nèi)存中的起始位置為16,長度為16鞠鲜,在內(nèi)存中的地址是16~31宁脊。
    有上述結(jié)果可得Struct4在內(nèi)存中占用32個(gè)字節(jié)断国,根據(jù)內(nèi)存對(duì)齊原則Struct4內(nèi)部包括子成員Struct1內(nèi)部最大成員為double8字節(jié)榆苞,所以Struct4最終占用的內(nèi)存大小為32字節(jié)稳衬。由此可得出下圖:
    Struct4內(nèi)存分布圖

以上就是我對(duì)內(nèi)存對(duì)齊原則的理解,如果有不同意見的同學(xué)歡迎留言給我坐漏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末薄疚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子仙畦,更是在濱河造成了極大的恐慌输涕,老刑警劉巖音婶,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慨畸,死亡現(xiàn)場離奇詭異,居然都是意外死亡衣式,警方通過查閱死者的電腦和手機(jī)寸士,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碴卧,“玉大人弱卡,你說我怎么就攤上這事∽〔幔” “怎么了婶博?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長荧飞。 經(jīng)常有香客問我凡人,道長,這世上最難降的妖魔是什么叹阔? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任挠轴,我火速辦了婚禮,結(jié)果婚禮上耳幢,老公的妹妹穿的比我還像新娘岸晦。我一直安慰自己,他們只是感情好睛藻,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布启上。 她就那樣靜靜地躺著,像睡著了一般店印。 火紅的嫁衣襯著肌膚如雪碧绞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天吱窝,我揣著相機(jī)與錄音讥邻,去河邊找鬼迫靖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛兴使,可吹牛的內(nèi)容都是我干的系宜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼发魄,長吁一口氣:“原來是場噩夢啊……” “哼盹牧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起励幼,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤汰寓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后苹粟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體有滑,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年嵌削,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毛好。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡苛秕,死狀恐怖肌访,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情艇劫,我是刑警寧澤吼驶,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站店煞,受9級(jí)特大地震影響蟹演,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浅缸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一轨帜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衩椒,春花似錦蚌父、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至阁将,卻和暖如春膏秫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背做盅。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工缤削, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窘哈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓亭敢,卻偏偏與公主長得像滚婉,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帅刀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359