基本資料大小
在這之前先來看下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個位元組是空的
type I8 int8 type I16 int16 type I32 int32 So(unsafe.Sizeof(struct { i8 I8 i16 I16 i32 I32 }{}), ShouldEqual, 8)
給型別重新命名之後,型別的大小並沒有改變
更多golang相關知識,請造訪golang教學欄位!