Golang內(nèi)存對(duì)齊

如何得到一個(gè)對(duì)象所占內(nèi)存大?。?/h2>
fmt.Println(unsafe.Sizeof(int64(0))) // "8"

type SizeOfA struct {
    A int
}
unsafe.Sizeof(SizeOfA{0}) // 8

type SizeOfC struct {
    A byte  // 1字節(jié)
    C int32 // 4字節(jié)
}
unsafe.Sizeof(SizeOfC{0, 0})    // 8
unsafe.Alignof(SizeOfC{0, 0}) // 4
結(jié)構(gòu)體中A byte占1字節(jié),C int32占4字節(jié). SizeOfC占8字節(jié)

內(nèi)存對(duì)齊:

為何會(huì)有內(nèi)存對(duì)齊?1.并不是所有硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)。2.性能原因 訪問(wèn)未對(duì)齊的內(nèi)存,處理器需要做兩次內(nèi)存訪問(wèn),而對(duì)齊的內(nèi)存只需訪問(wèn)一次。
上面代碼SizeOfC中元素一共5個(gè)字節(jié),而實(shí)際結(jié)構(gòu)體占8字節(jié)
是因?yàn)檫@個(gè)結(jié)構(gòu)體的對(duì)齊倍數(shù)Alignof(SizeOfC) = 4.也就是說(shuō),結(jié)構(gòu)體占的實(shí)際大小必須是4的倍數(shù),也就是8字節(jié)。

type SizeOfD struct {
    A byte
    B [5]int32
}
unsafe.Sizeof(SizeOfD{})   // 24
unsafe.Alignof(SizeOfD{})  // 4

Alignof返回的對(duì)齊數(shù)是結(jié)構(gòu)體中最大元素所占的內(nèi)存數(shù),不超過(guò)8,如果元素是數(shù)組那么取數(shù)組類(lèi)型所占的內(nèi)存值而不是整個(gè)數(shù)組的值

type SizeOfE struct {
    A byte  // 1
    B int64 // 8
    C byte  // 1
}
unsafe.Sizeof(SizeOfE{})    // 24
unsafe.Alignof(SizeOfE{}) // 8

SizeOfE中,元素的大小分別為1,8,1,但是實(shí)際結(jié)構(gòu)體占24字節(jié),遠(yuǎn)超元素實(shí)際大小,因?yàn)閮?nèi)存對(duì)齊原因,最開(kāi)始分配的8字節(jié)中包含了1字節(jié)的A,剩余的7字節(jié)不足以放下B,又為B分配了8字節(jié),剩余的C獨(dú)占再分配的8字節(jié)。

type SizeOfE struct {
    A byte  // 1
    C byte  // 1
    B int64 // 8    
}
unsafe.Sizeof(SizeOfE{})    // 16
unsafe.Alignof(SizeOfE{}) // 8

換一種寫(xiě)法,把A,C放到上面,B放到下面。這時(shí)SizeOfE占用的內(nèi)存變?yōu)榱?6字節(jié)。因?yàn)槭紫确峙涞?字節(jié)足以放下A和C,省去了8字節(jié)的空間。
上面一個(gè)結(jié)構(gòu)體中元素的不同順序足以導(dǎo)致內(nèi)存分配的巨大差異。前一種寫(xiě)法產(chǎn)生了很多的內(nèi)存空洞,導(dǎo)致結(jié)構(gòu)體不夠緊湊,造成內(nèi)存浪費(fèi)。

下面我們來(lái)看一下結(jié)構(gòu)體中元素的內(nèi)存布局:

unsafe.Offsetof:返回結(jié)構(gòu)體中元素所在內(nèi)存的偏移量

type SizeOfF struct {
    A byte
    C int16
    B int64
    D int32
}
unsafe.Offsetof(SizeOfF{}.A) // 0
unsafe.Offsetof(SizeOfF{}.C) // 2
unsafe.Offsetof(SizeOfF{}.B) // 8
unsafe.Offsetof(SizeOfF{}.D) // 16

下圖為內(nèi)存分布圖:


SizeOfF 內(nèi)存布局圖

藍(lán)色區(qū)域是元素實(shí)際所占內(nèi)存,灰色為內(nèi)存空洞。

下面總結(jié)一下go語(yǔ)言中各種類(lèi)型所占內(nèi)存大?。▁64環(huán)境下):

X64下1機(jī)器字節(jié)=8字節(jié)


Golang內(nèi)置類(lèi)型占用內(nèi)存大小

總結(jié)一下:

從例子中可以看出,結(jié)構(gòu)體中元素不同順序的排列會(huì)導(dǎo)致內(nèi)存分配的極大差異,不好的順序會(huì)產(chǎn)生許多的內(nèi)存空洞,造成大量?jī)?nèi)存浪費(fèi)。
雖然這幾個(gè)函數(shù)都在unsafe包中,但是他們并不是不安全的。在需要優(yōu)化內(nèi)存空間時(shí)這幾個(gè)函數(shù)非常有用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • unsafe 包簡(jiǎn)單說(shuō)明 unsafe,顧名思義,是不安全的,Go定義這個(gè)包名也是這個(gè)意思,讓我們盡可能的不要使用...
    Gopherzhang閱讀 1,645評(píng)論 8 3
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,684評(píng)論 1 32
  • 前言 Redis是目前最火爆的內(nèi)存數(shù)據(jù)庫(kù)之一,通過(guò)在內(nèi)存中讀寫(xiě)數(shù)據(jù),大大提高了讀寫(xiě)速度,可以說(shuō)Redis是實(shí)現(xiàn)網(wǎng)站...
    小陳阿飛閱讀 892評(píng)論 0 1
  • 感恩感謝被照顧。今天再次被我家榮榮的廚藝征服,自制全素麻辣香鍋,太棒了!還有佳佳大盆友蒸的米飯。 感恩感謝旁觀。今...
    enhui1994閱讀 222評(píng)論 0 1
  • 近來(lái)總是做夢(mèng),一做一個(gè)晚上。醒來(lái)什么都忘了,有時(shí)能記住一點(diǎn),有時(shí)一點(diǎn)也記不住了。 夢(mèng)終究是夢(mèng),它是見(jiàn)不了陽(yáng)光的。夢(mèng)...
    滴水穿石910閱讀 192評(píng)論 0 1

友情鏈接更多精彩內(nèi)容