內(nèi)存對齊

內(nèi)存對齊

概念:

百度百科內(nèi)存對齊:編譯器為程序中的每個(gè)“數(shù)據(jù)單元”安排在適當(dāng)?shù)奈恢蒙?/p>

為什么要對齊?

一種提高內(nèi)存訪問速度的策略,cpu在訪問未對齊的內(nèi)存需要經(jīng)過兩次內(nèi)存訪問肃廓,而經(jīng)過內(nèi)存對齊一次就可以了.

舉例說明: 32bit的系統(tǒng)一次只能讀入32bit的數(shù)據(jù), 即4個(gè)字節(jié), 如果首地址為0, name讀入順序應(yīng)該是0-3, 3-7, 8-11 ...... 這樣的讀入; 在沒有對齊的情況下, 一個(gè)int變量(4字節(jié))可能分配中2,3,4,5這幾個(gè)位置上, 如果要獲取該變量, 就要進(jìn)行0-3, 4-7兩次讀取

像下面的struct:

typedef strutc test{
    char a;
    int b;
    char c;
} 
  • 未對齊
image

讀取b需要0-3, 4-7兩次讀取

  • 對齊
image

讀取b就可以從4-7一次讀取

對齊規(guī)則

1. 內(nèi)存的自然對齊

每一種數(shù)據(jù)類型都必須放在地址中的整數(shù)倍上

  • char(1)類型可以放在任何位置
  • short(2)只能放在0x2, 1x2, 2x2, 3x2.., 即0, 2, 4, 6 ...的位置上
  • int(4)只能放在0x4, 1x4, 2x4, 3x4.., 即0, 4, 8, 12 ...的位置上
  • double(8)只能放在0x8, 1x8, 2x8, 3x8.., 即0, 8, 16, 24 ...的位置上

note:以上規(guī)則針對的是#pragma pack(16)#pragma pack(8)時(shí)適用, 對其系數(shù)為1,2,4, 參見下邊的說明

代碼:

#import "ViewController.h"

typedef struct test{
    char a;
    int b;
    double c;
    char d;
}STU;
@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    test();
}

int test(void)
{
    STU s;
    printf("s的大小是 = %d\n",(int)sizeof(STU));
    printf("s中a的起始地址是 %p\n",&(s.a));
    printf("s中b的起始地址是 %p\n",&(s.b));
    printf("s中c的起始地址是 %p\n",&(s.c));
    printf("s中d的起始地址是 %p\n",&(s.d));
    return 0;
}
@end

輸出:

s的大小是 = 24
s中a的起始地址是 0x7ffee06479c8
s中b的起始地址是 0x7ffee06479cc
s中c的起始地址是 0x7ffee06479d0
s中d的起始地址是 0x7ffee06479d8

如果按照規(guī)則一, 推斷出來的應(yīng)該是這樣的:

image

四字節(jié)對齊, 長度應(yīng)該是20位

結(jié)果其實(shí)是這樣的:

image

長度24位, 最后一個(gè)char補(bǔ)了7位, 原因就在于規(guī)則二

另外修改對齊系數(shù), 的出來的結(jié)果也不一樣:

pragma pack(16)
s的大小是 = 24
s中a的起始地址是 0x7ffee3e7f9c8
s中b的起始地址是 0x7ffee3e7f9cc
s中c的起始地址是 0x7ffee3e7f9d0
s中d的起始地址是 0x7ffee3e7f9d8
pragma pack(8)
大小是 = 24
s中a的起始地址是 0x7ffee2ab49c8
s中b的起始地址是 0x7ffee2ab49cc
s中c的起始地址是 0x7ffee2ab49d0
s中d的起始地址是 0x7ffee2ab49d8
pragma pack(4)
s的大小是 = 20
s中a的起始地址是 0x7ffee81239c8
s中b的起始地址是 0x7ffee81239cc
s中c的起始地址是 0x7ffee81239d0
s中d的起始地址是 0x7ffee81239d8
pragma pack(2)
s的大小是 = 16
s中a的起始地址是 0x7ffee03f09d0
s中b的起始地址是 0x7ffee03f09d2
s中c的起始地址是 0x7ffee03f09d6
s中d的起始地址是 0x7ffee03f09de

pragma pack(1)
s的大小是 = 14
s中a的起始地址是 0x7ffee2eb49d0
s中b的起始地址是 0x7ffee2eb49d1
s中c的起始地址是 0x7ffee2eb49d5
s中d的起始地址是 0x7ffee2eb49dd

2.補(bǔ)齊規(guī)則

在經(jīng)過第一原則分析后纽竣,檢查計(jì)算出的存儲單元是否為所有元素中最寬的元素的長度的整數(shù)倍廉涕,是戴已,則結(jié)束切平;
若不是,則補(bǔ)齊為它的整數(shù)倍

因?yàn)榇a中:

typedef struct test{
    char a;
    int b;
    double c;
    char d;
}STU;

struct的成員類型double是8位長度, 所以struct的大小必須是8的倍數(shù), 所以最后一位char要補(bǔ)上7位

3. 包含結(jié)構(gòu)體成員的補(bǔ)齊規(guī)則

如果結(jié)構(gòu)體作為成員点楼,則要找到這個(gè)結(jié)構(gòu)體中的最大元素扫尖,然后從這個(gè)最大成員的整數(shù)倍地址開始存儲

代碼:

typedef struct
{
    char a;
    int b;
    double c;
}X;

typedef struct {
    char a;
    X b;
}Y;

sizeof(X)為16,sizeof(Y)為24, 計(jì)算Y的存儲長度時(shí)掠廓,X的最大元素是double, 所以在存放第二個(gè)元素b時(shí)的初始位置是在double型的長度8的整數(shù)倍處换怖,而非16的整數(shù)倍處,即系統(tǒng)為b所分配的存儲空間是第8~23個(gè)字節(jié)

另外:包含指針類型的情況蟀瞧。只要記住指針本身所占的存儲空間是8個(gè)字節(jié)(64bit系統(tǒng), 32bit下是4字節(jié))就行了沉颂,而不必看它是指向什么類型的指針

typedef struct
{
    int* b;
}X;

typedef struct {
    char *a;
}Y;

輸出:

X的大小是 = 8
Y的大小是 = 8

對齊規(guī)則(百科中的描述)

每個(gè)特定平臺上的編譯器都有自己的默認(rèn)“對齊系數(shù)”(也叫對齊模數(shù))。程序員可以通過預(yù)編譯命令#pragma pack(n)悦污,n=1,2,4,8,16來改變這一系數(shù)铸屉,其中的n就是你要指定的“對齊系數(shù)”。

1塞关、數(shù)據(jù)成員對齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員抬探,第一個(gè)數(shù)據(jù)成員放在offset為0的地方子巾,以后每個(gè)數(shù)據(jù)成員的對齊按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長度中帆赢,比較小的那個(gè)進(jìn)行。

2线梗、結(jié)構(gòu)(或聯(lián)合)的整體對齊規(guī)則:在數(shù)據(jù)成員完成各自對齊之后椰于,結(jié)構(gòu)(或聯(lián)合)本身也要進(jìn)行對齊,對齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長度中仪搔,比較小的那個(gè)進(jìn)行瘾婿。

3、結(jié)合1、2可推斷:當(dāng)#pragma pack的n值等于或超過所有數(shù)據(jù)成員長度的時(shí)候偏陪,這個(gè)n值的大小將不產(chǎn)生任何效果抢呆。

32bit與64bit字節(jié)對比:

image

參考:

結(jié)構(gòu)體在內(nèi)存中的對其規(guī)則

內(nèi)存對齊與內(nèi)存分配原則

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市笛谦,隨后出現(xiàn)的幾起案子抱虐,更是在濱河造成了極大的恐慌,老刑警劉巖饥脑,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恳邀,死亡現(xiàn)場離奇詭異,居然都是意外死亡灶轰,警方通過查閱死者的電腦和手機(jī)谣沸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笋颤,“玉大人乳附,你說我怎么就攤上這事“槌危” “怎么了许溅?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秉版。 經(jīng)常有香客問我贤重,道長,這世上最難降的妖魔是什么清焕? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任并蝗,我火速辦了婚禮,結(jié)果婚禮上秸妥,老公的妹妹穿的比我還像新娘滚停。我一直安慰自己,他們只是感情好粥惧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布键畴。 她就那樣靜靜地躺著,像睡著了一般突雪。 火紅的嫁衣襯著肌膚如雪起惕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天咏删,我揣著相機(jī)與錄音惹想,去河邊找鬼。 笑死督函,一個(gè)胖子當(dāng)著我的面吹牛嘀粱,可吹牛的內(nèi)容都是我干的激挪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锋叨,長吁一口氣:“原來是場噩夢啊……” “哼垄分!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起娃磺,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤锋喜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后豌鸡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嘿般,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年涯冠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炉奴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛇更,死狀恐怖瞻赶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情派任,我是刑警寧澤砸逊,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站掌逛,受9級特大地震影響师逸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜豆混,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一篓像、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧皿伺,春花似錦员辩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至妒穴,卻和暖如春宋税,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宰翅。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工弃甥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爽室,地道東北人汁讼。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓淆攻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嘿架。 傳聞我的和親對象是個(gè)殘疾皇子瓶珊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

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

  • 源網(wǎng)址[英文] github上有大神翻譯了一篇內(nèi)存對齊的英文文獻(xiàn),我復(fù)現(xiàn)了一下過程耸彪; 發(fā)現(xiàn)其中有個(gè)地方有出入(st...
    十曰立閱讀 1,196評論 0 3
  • C語言是面向過程的伞芹,而C++是面向?qū)ο蟮?C和C++的區(qū)別: C是一個(gè)結(jié)構(gòu)化語言,它的重點(diǎn)在于算法和數(shù)據(jù)結(jié)構(gòu)蝉娜。C程...
    小辰帶你看世界閱讀 1,102評論 0 1
  • 首先通過一段代碼來描述內(nèi)存對齊的現(xiàn)象唱较。 上述代碼打印出來的結(jié)果為:12,8 為什么相同的結(jié)構(gòu)體,只是交換了變量 a...
    xuyafei86閱讀 2,989評論 2 15
  • 內(nèi)存對齊: 我們知道現(xiàn)代計(jì)算機(jī)體系中CPU按照雙字、字荧呐、字節(jié)訪問存儲內(nèi)存汉形,并通過總線進(jìn)行傳輸,若未經(jīng)一定規(guī)則的對齊...
    null122閱讀 9,488評論 12 40
  • 今天老師教了一個(gè)新的妝容-魅惑晚宴妝倍阐,明天要學(xué)習(xí)畫概疆,心里有點(diǎn)緊張之前的妝容都沒有熟悉清楚又有新的來了。下午我給和我...
    青空書屋閱讀 231評論 0 0