概念
對齊跟數(shù)據(jù)在內(nèi)存中的位置有關。如果一個變量的內(nèi)存地址正好位于它長度的整數(shù)倍,他就被稱做自然對齊。比如在32位cpu下,假設一個整型變量的地址為0x00000004,那它就是自然對齊的。
為什么要字節(jié)對齊
-
CPU每次尋址都是要消費時間的,并且CPU訪問內(nèi)存時,并不是逐個字節(jié)訪問,而是以字長(word size)為單位訪問,所以數(shù)據(jù)結構應該盡可能地在自然邊界上對齊,如果訪問未對齊的內(nèi)存,處理器需要做兩次內(nèi)存訪問,而對齊的內(nèi)存訪問僅需要一次訪問,內(nèi)存對齊后可以提升性能 - 有些
CPU可以訪問任意地址上的任意數(shù)據(jù),而有些CPU只能在特定地址訪問數(shù)據(jù),因此不同硬件平臺具有差異性,這樣的代碼就不具有移植性,如果在編譯時,將分配的內(nèi)存進行對齊,這就具有平臺可以移植性了
如何進行對齊?
- 基本數(shù)據(jù)類型:地址只要是它的長度的整數(shù)倍即可
- 數(shù)組:按照基本數(shù)據(jù)類型對齊,第一個對齊了后面的自然也就對齊了
- 聯(lián)合:按其包含的長度最大的數(shù)據(jù)類型對齊
- 結構體:結構體中每個數(shù)據(jù)類型都要對齊
對齊數(shù)
對齊數(shù) =編譯器默認值 與 成員自身大小 兩者的較小值
32位cpu上默認的指定對齊值是4字節(jié),64位cpu上默認的指定對齊值是8字節(jié)
對齊規(guī)則
- 第一個成員一定對齊,位于結構體變量偏移量(offset)為0的地址處。
- 其他成員要對齊到對齊數(shù)的整數(shù)倍的地址處(
當前起始偏移量 % min(成員大小, 對齊數(shù)) == 0) - 結構體 總大小必須為最大對齊數(shù)(每個成員都有一個對齊數(shù))的整數(shù)倍。
- 如果嵌套了結構體的情況,先按規(guī)則計算出嵌套的結構體大小,最后結構體的整體大小就是所有最大對齊數(shù)(含嵌套結構體的對齊數(shù))的整數(shù)倍。
舉例(golang)
// 64位平臺,對齊參數(shù)是8
type User struct {
A int32 // 4
B []int32 // 24 ,切片結構體中每個成員占用8字節(jié)
C string // 16 ,字符串結構體類型占用16字節(jié)
D bool // 1
}
對齊參數(shù)是8,int32、[]int32、string、bool對齊值分別是4、8、8、1,占用內(nèi)存大小分別是4、24、16、1,我們先根據(jù)第一條對齊規(guī)則分析User:
- 第一個字段類型是int32,對齊值是4,大小為4,所以放在內(nèi)存布局中的第一位.
- 第二個字段類型是[]int32,對齊值是8,大小為24,按照第一條規(guī)則,偏移量應該是成員大小24與對齊值8中較小那個的整數(shù)倍,那么偏移量就是8,所以4-7位會由編譯進行填充,一般為0值,也稱為空洞,第9到32位為第二個字段B.
- 第三個字段類型是string,對齊值是8,大小為16,所以他的內(nèi)存偏移值必須是8的倍數(shù),因為user前兩個字段就已經(jīng)排到了第32位,所以offset為32正好是8的倍數(shù),不要填充,從32位到48位是第三個字段C.
- 第四個字段類型是bool,對齊值是1,大小為1,所以他的內(nèi)存偏移值必須是1的倍數(shù),因為user前兩個字段就已經(jīng)排到了第48位,所以下一位的偏移量正好是48,正好是字段D的對齊值的倍數(shù),不用填充,可以直接排列到第四個字段,也就是從48到第49位是第三個字段D
?著作權歸作者所有:來自51CTO博客作者Golang夢工廠的原創(chuàng)作品,請聯(lián)系作者獲取轉(zhuǎn)載授權,否則將追究法律責任
詳解內(nèi)存對齊
https://blog.51cto.com/u_14523732/5707302