Golang 是否有必要內存對齊?

[導讀] go 語言內存對齊是什麼?有沒有必要在編碼時關注它?本文作者介紹了實際項目中內存對齊與優化的過程。

最近在做一些性能優化的工作,其中有個結構體佔用的空間比較大,而且在內存中的數量又特別多,就在想有沒有優化的空間,想起了 c 語言裏面的字節對齊,通過簡單地調整一下字段的順序,就能省出不少內存,這個思路在 golang 裏面同樣適用

基本數據大小

在這之前先來看下 golang 裏面基本的類型所佔數據的大小

So(unsafe.Sizeof(true), ShouldEqual, 1)
So(unsafe.Sizeof(int8(0)), ShouldEqual, 1)
So(unsafe.Sizeof(int16(0)), ShouldEqual, 2)
So(unsafe.Sizeof(int32(0)), ShouldEqual, 4)
So(unsafe.Sizeof(int64(0)), ShouldEqual, 8)
So(unsafe.Sizeof(int(0)), ShouldEqual, 8)
So(unsafe.Sizeof(float32(0)), ShouldEqual, 4)
So(unsafe.Sizeof(float64(0)), ShouldEqual, 8)
So(unsafe.Sizeof(""), ShouldEqual, 16)
So(unsafe.Sizeof("hello world"), ShouldEqual, 16)
So(unsafe.Sizeof([]int{}), ShouldEqual, 24)
So(unsafe.Sizeof([]int{1, 2, 3}), ShouldEqual, 24)
So(unsafe.Sizeof([3]int{1, 2, 3}), ShouldEqual, 24)
So(unsafe.Sizeof(map[string]string{}), ShouldEqual, 8)
So(unsafe.Sizeof(map[string]string{"1""one""2""two"}), ShouldEqual, 8)
So(unsafe.Sizeof(struct{}{}), ShouldEqual, 0)

字節對齊

結構體中的各個字段在內存中並不是緊湊排列的,而是按照字節對齊的,比如 int 佔 8 個字節,那麼就只能寫在地址爲 8 的倍數的地址處,至於爲什麼要字節對齊,主要是爲了效率考慮,而更深層的原理看了一下網上的說法,感覺不是很靠譜,就不瞎說了,感興趣可以自己研究下

// |x---|
So(unsafe.Sizeof(struct {
    i8 int8
}{}), ShouldEqual, 1)

簡單封裝一個 int8 的結構體,和 int8 一樣,僅佔 1 個字節,沒有額外空間

// |x---|xxxx|xx--|
So(unsafe.Sizeof(struct {
    i8  int8
    i32 int32
    i16 int16
}{}), ShouldEqual, 12)
// |x-xx|xxxx|
So(unsafe.Sizeof(struct {
    i8  int8
    i16 int16
    i32 int32
}{}), ShouldEqual, 8)

這兩個結構體裏面的內容完全一樣,調整了一下字段順序,節省了 33% 的空間

// |x---|xxxx|xx--|----|xxxx|xxxx|
So(unsafe.Sizeof(struct {
    i8  int8
    i32 int32
    i16 int16
    i64 int64
}{}), ShouldEqual, 24)
// |x-xx|xxxx|xxxx|xxxx|
So(unsafe.Sizeof(struct {
    i8  int8
    i16 int16
    i32 int32
    i64 int64
}{}), ShouldEqual, 16)

這裏需要注意的是 int64 只能出現在 8 的倍數的地址處,因此第一個結構體中,有連續的 4 個字節是空的

type I8 int8
type I16 int16
type I32 int32
So(unsafe.Sizeof(struct {
    i8  I8
    i16 I16
    i32 I32
}{}), ShouldEqual, 8)

給類型重命名之後,類型的大小並沒有發生改變

參考鏈接

測試代碼鏈接:github.com/hatlonely/hellogolang/blob/master/internal/buildin/struct_test.go

轉自:hatlonely

hatlonely.com/2018/03/17/golang-%E5%AD%97%E8%8A%82%E5%AF%B9%E9%BD%90/index.html

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/p-rEiJrEQTOARVOkVJLmuQ