解析struct的記憶體布局

2022-09-08 13:06:13 字數 2850 閱讀 7933

在平時開發過程中,我們常用map[string]struct{}來實現乙個set,用struct{}的原因是struct{}不占用記憶體空間,為什麼空struct會不占用記憶體空間?對於自定義的struct的記憶體空間的占用是什麼樣的?

struct和j**a中的物件類似,在記憶體中都是一塊連續的空間,在j**a中,物件的引用其實就是乙個物件在堆記憶體的記憶體位址起點,當訪問第n個物件時,就是訪問 (起點位址 + 第n個物件的位址偏移量)位置,在go中原理也類似,go struct的大小就是由struct中的屬性決定的,例如:

type a struct 

var a a

fmt.println(unsafe.sizeof(a)) // 3

可以看到輸出結果:3,表示乙個a物件在記憶體中占用3個位元組,此時的記憶體結構如下:

我們稍微修改一下欄位的型別,然後再看下結果

type b struct 

var b b

fmt.println(unsafe.sizeof(b)) // 12

這裡輸出結果會是8,按上面的理解int32占用4個位元組,再加上兩個1位元組的int8,應該輸出6才對,這個就引出go中的記憶體對齊機制了:

在計算機中,cpu在訪問記憶體時,每次訪問的並不是乙個位元組,而是乙個字(word),乙個字的字長由cpu的位數決定,例如32位的cpu乙個字長位32bit,也就是4個位元組,64位的cpu乙個字長64bit,也就是8個位元組,go為了減少在訪問物件時cpu與記憶體的互動次數,會在編譯時按照一定的規則進行記憶體對齊,防止訪問乙個物件的屬性需要經歷兩次匯流排週期。

假如上面的b物件如果是6位元組,則記憶體結構如下:

看上圖,此時的cpu字長位1位元組,那麼訪問y物件需要cpu需要和記憶體打兩次交道

所以go中進行記憶體對齊之後記憶體結構如下:

黃色部分為記憶體對齊部分,這樣在訪問屬性y時,cpu就只需要對記憶體進行一次讀取了。

內建unsafe包的sizeof函式用來獲取乙個變數的大小,另外還有內建unsafe包的alignof函式可以來獲取乙個變數的對齊係數,例如:

var a a

fmt.println(unsafe.alignof(a.x)) // 1

fmt.println(unsafe.alignof(a.y)) // 4

fmt.println(unsafe.alignof(a.z)) // 1

fmt.println(unsafe.alignof(a)) // 4

具體規則如下:

type c struct 

var c c

fmt.println(unsafe.sizeof(b)) // 8

此時的記憶體結構如下:

所以通過這個例子可以看出,合理的編排物件中屬性的位置,可以減少物件的記憶體大小

有了上面的基礎,可以推斷一下巢狀結構體和切片,陣列的unsafe.sizeof,unsafe.aligniof大小,來練習一下

type d struct 

var d d

fmt.println(unsafe.alignof(d)) // 8

fmt.println(unsafe.sizeof(d)) // 64

fmt.println("---------")

fmt.println(unsafe.alignof(d.x)) // 8

fmt.println(unsafe.sizeof(d.x)) // 8

fmt.println("---------")

fmt.println(unsafe.alignof(d.a)) // 1

fmt.println(unsafe.sizeof(d.a)) // 3

fmt.println("---------")

fmt.println(unsafe.alignof(d.b)) // 4

fmt.println(unsafe.sizeof(d.b)) // 12

fmt.println("---------")

fmt.println(unsafe.alignof(d.arr)) // 1

fmt.println(unsafe.sizeof(d.arr)) // 15

fmt.println("---------")

fmt.println(unsafe.alignof(d.sli)) // 8

fmt.println(unsafe.sizeof(d.sli)) // 24

其中a + b 做了記憶體對齊,填充了兩個位元組,arr也做了記憶體對齊,填充了乙個位元組

這裡為什麼切片是24個位元組呢,這個和切片的結構體有關,在runtime/slice.go中有對slice的定義:

這裡的len和cap在64位的cpu上都是占用8個位元組的,array是乙個指向底層陣列的指標,也是占用8個位元組,所以加起來一共就是24個位元組。

struct記憶體布局

結構體的記憶體分配原則原則1 資料成員對齊規則 結構 struct或聯合union 的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小的整數倍開始 比如int在32位機為4位元組,則要從4的整數倍位址開始儲存 原則2 結構體作為成員 如果乙個結構裡有某...

struct的記憶體布局

這段 的輸出結果是多少?4 1 5?那你就錯了 是8!為了cpu取數方便,提高效率,編譯器一般會把資料安排到合適的位置 一般數在記憶體中存放的起始位址都是4的倍數,稱為 4位元組對齊 所以在這裡,char雖然只佔1位元組,但是後面也給它填充3個位元組,湊夠4個位元組 struct s struct ...

STRUCT的記憶體

在c語言中,結構體的記憶體是由先到後順序占用空間的。先定義的在低位址,後定義的在高位址。位址採用空間對其策略。其實這是一篇問題貼,一直沒有弄懂是什麼問題!在結構體內存中 結構體首元素位址和結構體首位址一致。c 不一致 c 中,一般會空出開始的4位元組,為了區別物件位址,和第乙個成員的位址。通常是1位...