GO內存對齊

[問題]
在開始之前颖杏,先給大家看下go的各種基本類型在內存中所占大小情況:

func main() {
    fmt.Printf("bool size: %d\n", unsafe.Sizeof(bool(true)))
    fmt.Printf("int32 size: %d\n", unsafe.Sizeof(int32(0)))
    fmt.Printf("int8 size: %d\n", unsafe.Sizeof(int8(0)))
    fmt.Printf("int64 size: %d\n", unsafe.Sizeof(int64(0)))
    fmt.Printf("byte size: %d\n", unsafe.Sizeof(byte(0)))
    fmt.Printf("string size: %d\n", unsafe.Sizeof("EDDYCJY"))
}

輸出結果:

bool size: 1 //go中申請內存單位必須是2的整數(shù)次冪,最小內存單位為2^0=1byte
int32 size: 4
int8 size: 1
int64 size: 8
byte size: 1
string size: 16

有了以上結果坛芽,下面請大家計算一下留储,Part1結構體在內存中占空間大小為?

type Part1 struct {
    a bool
    b int32
    c int8
    d int64
    e byte
}

輸出結果:

func main() {
    part1 := Part1{}
    fmt.Printf("part1 size: %d, align: %d\n", unsafe.Sizeof(part1), unsafe.Alignof(part1))
}
//output:part1 size: 32, align: 8

最終輸出為32字節(jié)咙轩,與預期的 1+4+1+8+1=15不符获讳,為何?其實是編譯器在編譯階段會對它進行內存對齊而導致的活喊,要想理解這其中的奧秘丐膝,則需要認識什么是“內存對齊”了。

什么是內存對齊

在講什么是內存對齊之前,我們先來看個例子:


訪問未對齊內存示例

現(xiàn)有一片內存空間帅矗,首地址偏移量為0偎肃,其他采用相對地址。假設需要讀取右圖陰影部分字節(jié)數(shù)據(jù)损晤,其訪問過程如下:

  1. 首次讀取第一個內存塊 0-3 软棺,移除多余的0字節(jié)
  2. 讀取第二個內存塊 4-7 ,移除多余的5-7字節(jié)
  3. 合并1-4字節(jié)尤勋,讀出 xing.v 值,存入寄存器

對內存進行對齊后茵宪,內存地址分布為:


對齊內存訪問

此時訪問目標數(shù)據(jù)只需要 首地址+4*(2-1)即可最冰,效率提升了一半呢。

看完例子稀火,總結一下:內存對齊就是指編譯器在編譯階段對需要申請的內存地址(虛擬內存地址)進行處理(高位補零填充)暖哨,使cpu訪問任意內存數(shù)據(jù)都是一次訪問即可,提高訪存效率凰狞。

為什么要內存對齊

  1. 平臺兼容和移植性考慮(程序代碼通用性)
    不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的篇裁,例如特定硬件平臺只允許在特定地址獲取特定類型的數(shù)據(jù),否則會導致異常情況赡若。

  2. 性能原因(對cpu达布、內存方面有一定要求的話)
    若訪問未對齊的內存,將會導致cpu進行倆次內存訪問逾冬,并且需要花費額外的時鐘周期來處理對齊及運算黍聂。而對于已經(jīng)對齊的內存來說,只需一次訪問即可完成讀取指令動作身腻,效率大大提升产还。

  3. 某些硬件平臺(例如ARM)體系不支持未對齊的內存訪問

默認對齊系數(shù)

不同的平臺的編譯器都有自己默認的"對齊系數(shù)",可通過預編譯命令 #pragma pack(n) 更改對齊系數(shù),n代表想指定的系數(shù)大小嘀趟。一般常用的平臺系數(shù)如下:

  • 32位:4 字節(jié)
  • 64位:8 字節(jié)

如何對齊脐区?

首先查看每種類型的對齊系數(shù):

func main() {
    fmt.Printf("bool \talign: %d\n", unsafe.Alignof(true))
    fmt.Printf("int32 \talign: %d\n", unsafe.Alignof(int32(0)))
    fmt.Printf("int8 \talign: %d\n", unsafe.Alignof(int8(0)))
    fmt.Printf("int64 \talign: %d\n", unsafe.Alignof(int64(0)))
    fmt.Printf("byte \talign: %d\n", unsafe.Alignof(byte(0)))
    fmt.Printf("string \talign: %d\n", unsafe.Alignof("EDDYCJY"))
    fmt.Printf("map \talign: %d\n", unsafe.Alignof(map[string]string{}))
}

輸出

//單位: byte
bool    align: 1
int32   align: 4
int8    align: 1
int64   align: 8
byte    align: 1
string  align: 8
map     align: 8
slice   align: 8

golang可以使用unsafe.Alignof 查看每種類型的對齊系數(shù)。對齊系數(shù)一般為2^n次方她按,但由于類型的對齊系數(shù)不能超過默認對齊系數(shù)(電腦64win牛隅,默認系數(shù)=8),所以最大值為8.
[成員對齊規(guī)則]
1結構體變量首地址必須模運算對齊系數(shù)等于0,必須是對齊系數(shù)(也叫對齊邊界)的整數(shù)倍.
2.第一個成員變量的偏移量為0尤溜,往后的每個成員變量地址使用相對地址倔叼,對齊值必須為 編譯器對齊系數(shù)和成員變量類型對齊系數(shù)的最小值,成員變量偏移地址必須為對齊系數(shù)的整數(shù)倍

[結構體對齊規(guī)則]
除了結構體成員需要做對齊外宫莱,結構體本身也需要對齊丈攒,即所得最后的內存大小必須為對齊系數(shù)的整數(shù)倍,例如64位機器上,結構體成員對齊后大小位21字節(jié)巡验,在對結構體對齊時需要填充3字節(jié)际插,使得Sizeof(struct) 為對齊系數(shù)整數(shù)倍

最后

內存對齊主要是編譯器做的事情,對用戶代碼來說是透明的显设,某種層面來講框弛,程序員可以不關心這個。但作為一名專業(yè)過硬的程序員捕捂,去了解內存對齊很有必要瑟枫,在性能調優(yōu)場景,或者是海量數(shù)據(jù)場景 亦或是對于內存敏感的應用指攒,合理調整結構體的成員位置慷妙,分分鐘可以節(jié)省很多內存空間。(所以允悦,開篇提到的Part1結構體膝擂,明白為什么內存大小是32字節(jié)了嗎?)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末隙弛,一起剝皮案震驚了整個濱河市架馋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌全闷,老刑警劉巖叉寂,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異室埋,居然都是意外死亡办绝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門姚淆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來孕蝉,“玉大人,你說我怎么就攤上這事腌逢〗祷矗” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵搏讶,是天一觀的道長佳鳖。 經(jīng)常有香客問我,道長媒惕,這世上最難降的妖魔是什么系吩? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮妒蔚,結果婚禮上穿挨,老公的妹妹穿的比我還像新娘月弛。我一直安慰自己,他們只是感情好科盛,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布帽衙。 她就那樣靜靜地躺著,像睡著了一般贞绵。 火紅的嫁衣襯著肌膚如雪厉萝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天榨崩,我揣著相機與錄音谴垫,去河邊找鬼。 笑死母蛛,一個胖子當著我的面吹牛弹渔,可吹牛的內容都是我干的。 我是一名探鬼主播溯祸,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼舞肆!你這毒婦竟也來了焦辅?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤椿胯,失蹤者是張志新(化名)和其女友劉穎筷登,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哩盲,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡前方,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了廉油。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惠险。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抒线,靈堂內的尸體忽然破棺而出班巩,到底是詐尸還是另有隱情,我是刑警寧澤嘶炭,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布抱慌,位于F島的核電站,受9級特大地震影響眨猎,放射性物質發(fā)生泄漏抑进。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一睡陪、第九天 我趴在偏房一處隱蔽的房頂上張望寺渗。 院中可真熱鬧匿情,春花似錦努潘、人聲如沸夹抗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽他挎。三九已至拷橘,卻和暖如春恢筝,著一層夾襖步出監(jiān)牢的瞬間诞外,已是汗流浹背鲸伴。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工府蔗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人汞窗。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓姓赤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親仲吏。 傳聞我的和親對象是個殘疾皇子不铆,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內容