golang 字節對齊

最近在作一些性能優化的工做,其中有個結構體佔用的空間比較大,並且在內存中的數量又特別多,就在想有沒有優化的空間,想起了 c 語言裏面的字節對齊,經過簡單地調整一下字段的順序,就能省出很多內存,這個思路在 golang 裏面一樣適用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)
  • bool 類型雖然只有一位,但也須要佔用1個字節,由於計算機是以字節爲單位
  • 64爲的機器,一個 int 佔8個字節
  • string 類型佔16個字節,內部包含一個指向數據的指針(8個字節)和一個 int 的長度(8個字節)
  • slice 類型佔24個字節,內部包含一個指向數據的指針(8個字節)和一個 int 的長度(8個字節)和一個 int 的容量(8個字節)
  • map 類型佔8個字節,是一個指向 map 結構的指針
  • 能夠用 struct{} 表示空類型,這個類型不佔用任何空間,用這個做爲 map 的 value,能夠講 map 當作 set 來用

字節對齊

結構體中的各個字段在內存中並非緊湊排列的,而是按照字節對齊的,好比 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個字節是空的code

type I8 int8
type I16 int16
type I32 int32

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

給類型重命名以後,類型的大小並無發生改變內存

轉載請註明出處
本文連接: http://hatlonely.com/2018/03/...
相關文章
相關標籤/搜索