Golang優化之內存對齊

前文

話說今天在用uintptr進行指針運算的時候,突然想起來有個內存對齊的東西,那麼對這個uintptr計算是否會有影響?

帶着疑問,開始吧。

你將獲得以下知識點:
1.什麼是內存對齊?
2.爲什麼需要內存對齊?
3.如何進行內存對齊?
4.golang的內存對齊如何體現?
5.如何利用內存對齊來優化golang?

正文

1.什麼是內存對齊?

在想象中內存應該是一個一個獨立的字節組成的。像這樣:
在這裏插入圖片描述

事實上,人家是這樣的:
在這裏插入圖片描述

內存是按照成員的聲明順序,依次分配內存,第一個成員偏移量是0,其餘每個成員的偏移量爲指定數的整數倍數(圖中是4)。像這樣進行內存的分配叫做內存對齊。

2.爲什麼需要內存對齊?

原因有兩點:

平臺原因

並不是所有的硬件平臺都能訪問任意地址上的任意數據,會直接報錯的!
(解釋:比如說有的cpu讀取4個字節數據,要是沒有內存對齊,從1開始那麼內存就需要把0-7字節的全部取出來,再剔除掉1/5/6/7,增加了額外的操作,cpu不一定能這麼搞,自然就報錯了)

性能原因

訪問未對齊的內存,需要訪問兩次;如果對齊的話就只需要一次了。
(解釋:比如取int64,按照8個位對齊好了,那獲取的話直接就是獲取8個字節就好了,邊界好判斷)

3.如何進行內存對齊?

二個原則:
1.具體類型,對齊值=min(編譯器默認對齊值,類型大小Sizeof長度)
2.struct每個字段內部對齊,對齊值=min(默認對齊值,字段最大類型長度)

4.golang的內存對齊如何體現?

4.1 結構體的相同成員不同順序

結構體是平時寫代碼經常用到的。相同的成員,不同的排列順序,會有什麼區別嗎?

舉個例子:

func main() {
	fmt.Println(unsafe.Sizeof(struct {
		i8  int8
		i16 int16
		i32 int32
	}{}))
	fmt.Println(unsafe.Sizeof(struct {
		i8  int8
		i32 int32
		i16 int16
	}{}))
}

輸出:

8
12

what?竟然不一樣。
分析一波:需要內存對齊的話,因爲最大是int32,所以最終記過必須是4個字節的倍數才能對齊。
當8-16-32的時候,類似這樣|x-xx|xxxx|。
當8-32-16的時候,類似這樣|x—|xxxx|xx–|。
一眼就看出了大小了。

這裏的爲什麼是x-xx而不是xxx-需要說明下。因爲當int8放入內存的時候,其佔坑1個字節,對齊值爲1,而int16佔坑2個字節,對齊值爲2,所以說會先偏移2個字節從第三個字節纔開始放int16的數

4.2指針運算

現在對結構體Test通過指針計算的方式進行賦值。
Test內存情況:|x-xx|xxxx|。需要注意的是這裏的“-”需要多計算一個字節才行。

type Test struct {
	i8  int8
	i16 int16
	i32 int32
}


func main() {
	var t = new(Test)
	// 從0開始
	var i8 = (*int8)(unsafe.Pointer(t))
	*i8 = int8(10)
	
	// 偏移int8+1的字節數,注意這裏有個1!!! 
	var i16 = (*int16)(unsafe.Pointer(uintptr(unsafe.Pointer(t))+ uintptr(1)  + uintptr(unsafe.Sizeof(int8(0)))))
	*i16 = int16(10)

	// 偏移int8+1+int16+的字節數,注意這裏有個1!!! 
	var i32 = (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) + uintptr(1) + uintptr(unsafe.Sizeof(int8(0))+uintptr(unsafe.Sizeof(int16(0))))))
	*i32 = int32(10)
	fmt.Println(*t)
}

輸出:

{10 10 10}

附上兩個神器:

功能 函數
獲取對齊值 unsafe.Alignof(t.i16)
獲取偏移值 unsafe.Offsetof(t.i16)

5.如何利用內存對齊來優化golang?

5.1 結構體佔用內存過大的問題

根據計算對齊值進行成員順序的拼湊,可以一定程度上縮小結構體佔用的內存。

5.2 指針運算的坑

通過分析偏移量和對齊值,準確計算每個成員所偏移的位數,避免算錯。

延伸閱讀

Go語言實戰筆記(二十六)| Go unsafe 包之內存佈局

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章