91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

golang內存對齊的概念是什么

發布時間:2022-02-07 10:32:47 來源:億速云 閱讀:146 作者:iii 欄目:開發技術

這篇文章主要介紹“golang內存對齊的概念是什么”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“golang內存對齊的概念是什么”文章能幫助大家解決問題。

什么是內存對齊

為保證程序順利高效的運行,編譯器會把各種類型的數據安排到合適的地址,并占用合適的長度,這就是內存對齊。

每種類型的對齊值就是它的對齊邊界,內存對齊要求數據存儲地址以及占用的字節數都要是它的對齊邊界的倍數。所以下述的int32要錯開兩個字節,從4開始存,卻不能緊接著從2開始。

golang內存對齊的概念是什么

也可以這樣解釋:

CPU把內存當成是一塊一塊的,塊的大小可以是2,4,8,16字節大小,因此CPU在讀取內存時是一塊一塊進行讀取的。塊大小成為memory access granularity(粒度)。

如果不進行內存對齊

比如我們想從地址1開始讀8字節的數據:

golang內存對齊的概念是什么

CPU會分兩次讀:

  • 第一次從 0 - 7 但只取后 7 字節。

  • 第二次從 8 - 15 但只取第 1 字節。

分兩次讀,這樣勢必會對性能造成影響。

為什么要內存對齊

原因主要有兩點:

  • 平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數據的;某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常。

  • 性能原因:數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內存,處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問。

對齊邊界

那該怎么確定每種數據的對齊邊界呢?這和平臺有關,go語言支持這些平臺:

可以看到常見的32位平臺,指針寬度和寄存器寬度都是4字節,64位平臺上都是8字節。而被go語言稱為寄存器寬度的這個值,就可以理解為機器字長,也是平臺對應的最大對齊邊界。

golang內存對齊的概念是什么

而數據類型的對齊邊界,是取類型大小與平臺最大對齊邊界中較小的那個。不過要注意,同一個類型在不同平臺上,大小可能不同,對齊邊界也可能不同。

golang內存對齊的概念是什么

為什么不統一使用平臺最大對齊邊界呢?或者統一按各類型大小來對齊呢?

我們來試一下,假設目前是64位平臺,最大對齊邊界為8字節。int8只有1字節,按照1字節對齊的話,它可以放在任何位置,因為總能通過一次讀取把它完整拿出來。如果統一對齊到8字節,雖然同樣只要讀取一次,但每個int8的變量都要浪費7字節,所以對齊到1。

golang內存對齊的概念是什么

int16占2字節,按照2字節對齊,可以從這些地址開始存,而且能保證只用讀取一次。

golang內存對齊的概念是什么

如果按1字節對齊就可能存成這樣,那就要讀取兩次再截取拼接,會影響性能。

golang內存對齊的概念是什么

如果按8字節對齊,會與int8一樣浪費內存,所以對齊到2。

這是小于最大對齊邊界的情況,再來看看大于的情況。

假設要在32位的平臺下存儲一個int64類型的數據,在0和1位置被占用的情況下,就要從位置8開始存。而如果對齊到4,就可以從位置4開始,內存浪費更少,所以選擇對齊到4。

golang內存對齊的概念是什么

因此類型對齊邊界會這樣選擇,依然是為了減少浪費提升性能。

golang內存對齊的概念是什么

GO 計算對齊邊界函數

在go語言中可以調用 unsafe.Alignof 來返回相應類型的對齊邊界:

func main() {
	fmt.Printf("bool align: %d\n", unsafe.Alignof(bool(true)))
	fmt.Printf("int32 align: %d\n", unsafe.Alignof(int32(0)))
	fmt.Printf("int8 align: %d\n", unsafe.Alignof(int8(0)))
	fmt.Printf("int64 align: %d\n", unsafe.Alignof(int64(0)))
	fmt.Printf("byte align: %d\n", unsafe.Alignof(byte(0)))
	fmt.Printf("string align: %d\n", unsafe.Alignof("EDDYCJY"))
	fmt.Printf("map align: %d\n", unsafe.Alignof(map[string]string{}))
}

運行結果:

bool align: 1
int32 align: 4
int8 align: 1
int64 align: 8
byte align: 1
string align: 8
map align: 8

確定結構體的對齊邊界

對結構體而言,首先要確定每個成員的對齊邊界,然后取其中最大的,這就是這個結構體的對齊邊界。

golang內存對齊的概念是什么

然后來存儲這個結構體變量:

內存對齊要求一:

  • 存儲這個結構體的起始地址,是對齊邊界的倍數。

假設從0開始存,結構體的每個成員在存儲時,都要把這個起始地址當作地址0,然后再用相對地址來決定自己該放在哪里。

內存對齊要求2:

  • 結構體整體占用字節數需要是類型對齊邊界的倍數,不夠的話要往后擴張一下。

所以最終上述結構體類型的大小就是24字節。

案例

type Part1 struct {
	a bool
	b int32
	c int8
	d int64
	e byte
}
type Part2 struct {
	a bool
	c int8
	e byte
	b int32 // 4個字節
	d int64
}

分別求以上兩個結構體占用的字節:

fmt.Printf("part1 size: %d, align: %d\n", unsafe.Sizeof(part1), unsafe.Alignof(part1))
fmt.Printf("part2 size: %d, align: %d\n", unsafe.Sizeof(part2), unsafe.Alignof(part2))

這里我們直接調用函數求得:

part1 size: 32, align: 8
part2 size: 16, align: 8

關于“golang內存對齊的概念是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

桂林市| 海盐县| 台江县| 抚州市| 金平| 剑阁县| 新泰市| 赫章县| 海盐县| 邹城市| 利辛县| 高密市| 蒲城县| 渭南市| 陕西省| 宝兴县| 灌阳县| 钟祥市| 崇明县| 玛纳斯县| 新竹市| 江川县| 张家界市| 吉安县| 襄汾县| 临夏市| 辉县市| 连山| 平阴县| 平顺县| 祁东县| 鸡泽县| 万盛区| 博湖县| 岳西县| 江安县| 静海县| 通州市| 明光市| 灵山县| 宾阳县|