使用記憶體對齊機制優化結構體性能,妙啊! 可以簡單理解為:將對齊繫數小的欄位,儘可能放在一起,儘量減少空白填充。 掌握了記憶體對齊機制後,結構體Struct的優化,調整下欄位順序,效果立竿見影。記憶體對齊其實就是典型的空間換時間的方式,來達到優化的目的。牢記對齊原則,對實際場景進行分析,減少空白填充。 ...
使用記憶體對齊機制優化結構體性能,妙啊!
前言
之前分享過2篇結構體文章:
10秒改struct性能直接提升15%,產品姐姐都誇我好棒 和 Go語言空結構體這3種妙用,你知道嗎? 得到了大家的好評。
這篇繼續分享進階內容:
結構體的定義,大家都很熟悉,想要定義出更節省記憶體空間的結構體,可不是一件簡單的事。
我們必須掌握Go的結構體記憶體對齊機制,才能做出相應的優化:節省記憶體並提高性能。
先來看個例子
下麵定義兩個結構體,欄位都一樣,只是部分欄位稍微調整了一下順序。
但輸出的結果卻完全不同:一個順序調整就節省了8個位元組,太神奇了。
type BadSt struct {
A int32
B int64
C bool
}
type GoodSt struct {
A int32
C bool
B int64
}
func main() {
bad := BadSt{A: 10, B: 20, C: false}
fmt.Println(unsafe.Sizeof(bad))//輸出結果:24
good := GoodSt{A: 10, B: 20, C: false}
fmt.Println(unsafe.Sizeof(good))//輸出結果:16
}
為什麼bad占用24位元組,而good卻只占用16位元組呢?
想要解開這個問題,我們得先來學習一下記憶體對齊機制,然後再來進一步分析。
原理講解
基本概念
為了能讓CPU可以更快的存儲、讀取到各個欄位,Go編譯器會幫我們把結構體做數據的對齊。
所謂的數據對齊,是指記憶體地址的大小是所存儲數據大小的整數倍(按位元組為單位),以便CPU可以一次將該數據從記憶體中讀取出來,減少了讀取次數。
編譯器通過在結構體的各個欄位之間填充一些空白,來達到對齊的目的。
CPU訪問記憶體
CPU 訪問記憶體時,並不是逐個位元組訪問,而是以機器字(word)為單位進行訪問。
比如 64位CPU的字長(word size)為8bytes,那麼CPU訪問記憶體的單位也是8位元組,每次載入的記憶體數據也是固定的若幹字長,如8words(64bytes)、16words(128bytes)等
對齊繫數
不同硬體平臺占用的大小和對齊值都可能是不一樣的,每個特定平臺上的編譯器都有自己的預設"對齊繫數",32位系統對齊繫數是4,64位系統對齊繫數是8
不同類型的對齊繫數也可能不一樣,使用Go
語言中的unsafe.Alignof
函數可以返回相應類型的對齊繫數,對齊繫數都符合2^n
這個規律,最大也不會超過8
func main() {
fmt.Printf("bool: %d\n", unsafe.Alignof(bool(true)))
fmt.Printf("string: %d\n", unsafe.Alignof(string("a")))
fmt.Printf("int: %d\n", unsafe.Alignof(int(0)))
fmt.Printf("int32: %d\n", unsafe.Alignof(int32(0)))
fmt.Printf("int64: %d\n", unsafe.Alignof(int64(0)))
fmt.Printf("float64: %d\n", unsafe.Alignof(float64(0)))
fmt.Printf("float32:%d\n", unsafe.Alignof(float32(0)))
}
//輸出結果:
//bool: 1
//string: 8
//int: 8
//int32: 4
//int64: 8
//float64:8
//float32:4
對齊原則
- 結構體變數中成員的偏移量必須是成員大小的整數倍
- 整個結構體的記憶體大小必須是最大位元組的整數倍(結構體的記憶體占用是1/4/8/16byte…)
案例分析
type BadSt struct {
A int32
B int64
C bool
}
BadSt結構體,占用24個位元組
分析過程:
- 欄位A 4位元組:先計算偏移量,最開頭下標為0,0%4=0,正好整除,先占用4個位元組;
- 欄位B 8位元組:下標4-7,對8都不能整除,則填充空白,下標8可以整除,所以下標8-15 8個位元組為欄位B的存儲使用;
- 欄位C 1位元組:下標16,對1可以整除,所以下標16則用作欄位C的存儲;
- 最後,該結構體欄位最大位元組為8且目前已占用17位元組,要保證是整數倍,所以最後面需要填充7個位元組,占滿24位元組,才能滿足條件(對齊原則2)。
GoodSt結構體,占用16個位元組
type GoodSt struct {
A int32
C bool
B int64
}
分析過程:
- 欄位A 4位元組:先計算偏移量,最開頭下標為0,0%4=0,正好整除,先占用4個位元組;
- 欄位C 1位元組:下標4,對1可以整除,所以下標4則用作欄位C的存儲;
- 欄位B 8位元組:下標5-7,對8都不能整除,則填充空白,下標8可以整除,所以下標8-15 8個位元組為欄位B的存儲使用;
- 最後,該結構體欄位最大位元組為8且目前已占用16位元組,正好是整數倍,所以後面不再需要填充空白了。
總結
通過上文的原理講解和案例分析,我們發現記憶體對齊機制並不複雜。
可以簡單理解為:將對齊繫數小的欄位,儘可能放在一起,儘量減少空白填充。
掌握了記憶體對齊機制後,結構體Struct的優化,調整下欄位順序,效果立竿見影。記憶體對齊其實就是典型的空間換時間的方式,來達到優化的目的。牢記對齊原則,對實際場景進行分析,減少空白填充。
原文鏈接:https://mp.weixin.qq.com/s/64eWxeB0xxA65HZc65axHQ
一起學習
需要簡歷優化和就業輔導的朋友可以私信我,也歡迎關註我的公眾號:
我的文章首發在我的公眾號: 程式員升職加薪之旅,歡迎大家關註,第一時間閱讀我的文章。
也歡迎大家關註我,點贊、留言、轉發。你的支持,是我更文的最大動力!