結(jié)構(gòu)體內(nèi)存分析

1. 什么是內(nèi)存對齊

看下面的小程序辕漂,理論上,int4 byte尼摹,char占一個1 byte见芹,那么將它們放到一個結(jié)構(gòu)體中應(yīng)該占4+1=5byte剂娄,但是實際上,通過運行程序得到的結(jié)果是8 byte玄呛,這就是內(nèi)存對齊所導(dǎo)致的阅懦。

struct Struct {
    int a;  // 4
    char b; // 1
}struct4;

NSLog(@"%lu",sizeof(struct4)); // 輸出為 8

計算機中內(nèi)存空間都是按照 byte 劃分的,從理論上講似乎對任何類型的變量的訪問可以從任何地址開始徘铝,但是實際的計算機系統(tǒng)對基本類型數(shù)據(jù)在內(nèi)存中存放的位置有限制耳胎,它們會要求這些數(shù)據(jù)的首地址的值是某個數(shù)k(通常它為48)的倍數(shù),這就是所謂的內(nèi)存對齊惕它。

2. 為什么要內(nèi)存對齊

平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的场晶;某些硬件平臺只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常怠缸。

計算機的處理器是以一定大小的塊來進行讀取的诗轻,這作為我們的前提條件。

對齊跟數(shù)據(jù)在內(nèi)存中的位置有關(guān)揭北。如果一個變量的內(nèi)存地址剛好位于它本身長度的整數(shù)倍扳炬,他就被稱做自然對齊。例如一個整型變量(占4字節(jié))的地址為0x00000008搔体,那它就是自然對齊的恨樟。

現(xiàn)在假設(shè)一個整型變量(4字節(jié))不是自然對齊的,它的起始地址落在0x00000002(圖中藍色區(qū)域)疚俱,處理器想要訪問它的值劝术,按照4字節(jié)的塊進行讀取,從圖中的0x00起讀呆奕,讀取4字節(jié)大小养晋,讀到0x03

image.png

這樣的一次讀取之后,我們并不能取到我們要訪問的整型數(shù)據(jù)梁钾,緊接著處理器會繼續(xù)再往下讀绳泉,偏移4個字節(jié),從0x04開始姆泻,讀到0x07

image.png

到這一步零酪,處理器才能讀取到了我們需要訪問的內(nèi)存數(shù)據(jù),當(dāng)然這中間還存在剔除與合并的過程拇勃。在上面的例子中四苇,要讀取兩次才能獲取到我們想要的數(shù)據(jù)。

那么如果是內(nèi)存對齊的呢方咆?

image.png

由上圖可知月腋,只要讀取一次就能獲取到相應(yīng)的數(shù)據(jù)。

因此可以得出,內(nèi)存是否對齊罗售,會影響到數(shù)據(jù)的讀取效率辜窑。另外不同的內(nèi)存存取粒度對同一任務(wù)也有不同影響钩述,這里我們不過多的討論寨躁。

3.內(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ù)倍開始(比如int4字節(jié),則要從4的整數(shù)倍地址開始存儲方面。
  2. 結(jié)構(gòu)體作為成員:如果一個結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開始存儲.(struct a里存有struct b,b里有char放钦、intdouble等元素,那b應(yīng)該從8的整數(shù)倍開始存儲.)
  3. 收尾工作:結(jié)構(gòu)體的總大小,也就是sizeof的結(jié)果,必須是其內(nèi)部最大成員的整數(shù)倍恭金,不足的要補?操禀。

按我自己的理解來看:

  • 對于規(guī)則1 每個數(shù)據(jù)成員的起始位置,都是自身大小的整數(shù)倍横腿。
  • 對于規(guī)則2 對于結(jié)構(gòu)體做為成員變量颓屑,起始位置要根據(jù)自身成員變量最大的元素來確定。

下面我們來看一個簡單的例子:

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

double的大小為8個字節(jié),按照規(guī)則1耿焊, a成員變量將會占據(jù)前首地址開始的 8個字節(jié)揪惦。也就是0x000x07的地址。
char的大小為1,按照規(guī)則1罗侯,內(nèi)存中的第9為是1的倍數(shù)器腋,占據(jù)一個字節(jié)0x08,單數(shù)成員變量c,為int類型,大小為4钩杰,內(nèi)存中的第10為并不是4的倍數(shù)纫塌,所以并不能滿足規(guī)則1。因此讲弄,成員變量b要補3個位置护戳,即占據(jù)0x080x11的地址單元,成員變量c0x120x15開始占據(jù)4個內(nèi)存單元垂睬。同理媳荒,按照規(guī)則1可以得出成員變量d占據(jù)0x160x08的內(nèi)存單元,總共占據(jù)18個字節(jié)驹饺。最后钳枕,我們進行收尾工作:結(jié)構(gòu)體的總大小,必須是其內(nèi)部最大成員的整數(shù)倍赏壹。內(nèi)部最大成員為double 8個字節(jié)鱼炒,可以計算出結(jié)構(gòu)的總大小為24

最后我們用代碼來驗證下:

image.png

如果結(jié)構(gòu)體中存在結(jié)構(gòu)體成員變量會怎樣蝌借?

struct TestStruct2 {
    double a; // 8
    int b;    // 4
    char c;   // 1
    short d;  // 2
    int e;    // 4
    struct TestStruct1 str;
}struct2;

按照規(guī)則1昔瞧,可以得出前5個變量占據(jù)24個內(nèi)存單元指蚁,對于結(jié)構(gòu)體成員str,其內(nèi)部最大成員為double 8個字節(jié)自晰,而248的倍數(shù)凝化,符合規(guī)則1str占據(jù)后面24個字節(jié)單元酬荞。此時搓劫,結(jié)構(gòu)體總共占據(jù)48個內(nèi)存單元,按照規(guī)則3 TestStruct2的最大成員是 TestStruct1 str 24個字節(jié)混巧,符合規(guī)則枪向。
下面我么用代碼驗證下結(jié)果

image.png

4. 總結(jié)

其實,內(nèi)存對齊就是定制了一套規(guī)則咧党,以合理的利用內(nèi)存空間并提高內(nèi)存訪問效率秘蛔。 編譯器通過適當(dāng)增加padding,使每個成員的訪問都在一個指令里完成傍衡,而不需要多次訪問再拼接深员。是一個以空間換時間的過程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末聪舒,一起剝皮案震驚了整個濱河市辨液,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌箱残,老刑警劉巖滔迈,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異被辑,居然都是意外死亡燎悍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門盼理,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谈山,“玉大人,你說我怎么就攤上這事宏怔∽嗦罚” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵臊诊,是天一觀的道長鸽粉。 經(jīng)常有香客問我,道長抓艳,這世上最難降的妖魔是什么触机? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上儡首,老公的妹妹穿的比我還像新娘片任。我一直安慰自己,他們只是感情好蔬胯,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布对供。 她就那樣靜靜地躺著,像睡著了一般笔宿。 火紅的嫁衣襯著肌膚如雪犁钟。 梳的紋絲不亂的頭發(fā)上棱诱,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天泼橘,我揣著相機與錄音,去河邊找鬼迈勋。 笑死炬灭,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的靡菇。 我是一名探鬼主播重归,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼厦凤!你這毒婦竟也來了鼻吮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤较鼓,失蹤者是張志新(化名)和其女友劉穎椎木,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體博烂,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡香椎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了禽篱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畜伐。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖躺率,靈堂內(nèi)的尸體忽然破棺而出玛界,到底是詐尸還是另有隱情,我是刑警寧澤悼吱,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布慎框,位于F島的核電站,受9級特大地震影響舆绎,放射性物質(zhì)發(fā)生泄漏鲤脏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望猎醇。 院中可真熱鬧窥突,春花似錦、人聲如沸硫嘶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沦疾。三九已至称近,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哮塞,已是汗流浹背刨秆。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留忆畅,地道東北人衡未。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像家凯,于是被迫代替她去往敵國和親缓醋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容