概念
對(duì)齊跟數(shù)據(jù)在內(nèi)存中的位置有關(guān)粒氧。如果一個(gè)變量的內(nèi)存地址正好位于它長(zhǎng)度的整數(shù)倍馍忽,他就被稱做自然對(duì)齊侨嘀。比如在32
位cpu
下型宝,假設(shè)一個(gè)整型變量的地址為0x00000004
,那它就是自然對(duì)齊的絮爷。
為什么要字節(jié)對(duì)齊
-
CPU
每次尋址都是要消費(fèi)時(shí)間的趴酣,并且CPU
訪問(wèn)內(nèi)存時(shí),并不是逐個(gè)字節(jié)訪問(wèn)坑夯,而是以字長(zhǎng)(word size
)為單位訪問(wèn)岖寞,所以數(shù)據(jù)結(jié)構(gòu)應(yīng)該盡可能地在自然邊界上對(duì)齊,如果訪問(wèn)未對(duì)齊的內(nèi)存柜蜈,處理器需要做兩次內(nèi)存訪問(wèn)仗谆,而對(duì)齊的內(nèi)存訪問(wèn)僅需要一次訪問(wèn),內(nèi)存對(duì)齊后可以提升性能 - 有些
CPU
可以訪問(wèn)任意地址上的任意數(shù)據(jù)淑履,而有些CPU
只能在特定地址訪問(wèn)數(shù)據(jù)隶垮,因此不同硬件平臺(tái)具有差異性,這樣的代碼就不具有移植性秘噪,如果在編譯時(shí)狸吞,將分配的內(nèi)存進(jìn)行對(duì)齊,這就具有平臺(tái)可以移植性了
如何進(jìn)行對(duì)齊指煎?
- 基本數(shù)據(jù)類型:地址只要是它的長(zhǎng)度的整數(shù)倍即可
- 數(shù)組:按照基本數(shù)據(jù)類型對(duì)齊蹋偏,第一個(gè)對(duì)齊了后面的自然也就對(duì)齊了
- 聯(lián)合:按其包含的長(zhǎng)度最大的數(shù)據(jù)類型對(duì)齊
- 結(jié)構(gòu)體:結(jié)構(gòu)體中每個(gè)數(shù)據(jù)類型都要對(duì)齊
對(duì)齊數(shù)
對(duì)齊數(shù)
=編譯器默認(rèn)值
與 成員自身大小
兩者的較小值
32位cpu上默認(rèn)的指定對(duì)齊值是4
字節(jié),64位cpu上默認(rèn)的指定對(duì)齊值是8
字節(jié)
對(duì)齊規(guī)則
- 第一個(gè)成員一定對(duì)齊,位于結(jié)構(gòu)體變量偏移量(offset)為0的地址處至壤。
- 其他成員要對(duì)齊到對(duì)齊數(shù)的整數(shù)倍的地址處(
當(dāng)前起始偏移量 % min(成員大小威始, 對(duì)齊數(shù)) == 0
) - 結(jié)構(gòu)體 總大小必須為最大對(duì)齊數(shù)(每個(gè)成員都有一個(gè)對(duì)齊數(shù))的整數(shù)倍。
- 如果嵌套了結(jié)構(gòu)體的情況像街,先按規(guī)則計(jì)算出嵌套的結(jié)構(gòu)體大小黎棠,最后結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍晋渺。
舉例(golang)
// 64位平臺(tái),對(duì)齊參數(shù)是8
type User struct {
A int32 // 4
B []int32 // 24 葫掉,切片結(jié)構(gòu)體中每個(gè)成員占用8字節(jié)
C string // 16 些举,字符串結(jié)構(gòu)體類型占用16字節(jié)
D bool // 1
}
對(duì)齊參數(shù)是8,int32俭厚、[]int32户魏、string、bool對(duì)齊值分別是4挪挤、8叼丑、8、1扛门,占用內(nèi)存大小分別是4鸠信、24、16论寨、1星立,我們先根據(jù)第一條對(duì)齊規(guī)則分析User:
- 第一個(gè)字段類型是int32,對(duì)齊值是4葬凳,大小為4绰垂,所以放在內(nèi)存布局中的第一位.
- 第二個(gè)字段類型是[]int32,對(duì)齊值是8火焰,大小為24劲装,按照第一條規(guī)則,偏移量應(yīng)該是成員大小24與對(duì)齊值8中較小那個(gè)的整數(shù)倍昌简,那么偏移量就是8占业,所以4-7位會(huì)由編譯進(jìn)行填充,一般為0值纯赎,也稱為空洞谦疾,第9到32位為第二個(gè)字段B.
- 第三個(gè)字段類型是string,對(duì)齊值是8犬金,大小為16餐蔬,所以他的內(nèi)存偏移值必須是8的倍數(shù),因?yàn)閡ser前兩個(gè)字段就已經(jīng)排到了第32位佑附,所以offset為32正好是8的倍數(shù)樊诺,不要填充,從32位到48位是第三個(gè)字段C.
- 第四個(gè)字段類型是bool音同,對(duì)齊值是1词爬,大小為1,所以他的內(nèi)存偏移值必須是1的倍數(shù)权均,因?yàn)閡ser前兩個(gè)字段就已經(jīng)排到了第48位顿膨,所以下一位的偏移量正好是48锅锨,正好是字段D的對(duì)齊值的倍數(shù),不用填充恋沃,可以直接排列到第四個(gè)字段必搞,也就是從48到第49位是第三個(gè)字段D
?著作權(quán)歸作者所有:來(lái)自51CTO博客作者Golang夢(mèng)工廠的原創(chuàng)作品,請(qǐng)聯(lián)系作者獲取轉(zhuǎn)載授權(quán)囊咏,否則將追究法律責(zé)任
詳解內(nèi)存對(duì)齊
https://blog.51cto.com/u_14523732/5707302