W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
原文鏈接:https://gopl-zh.github.io/ch13/ch13-01.html
unsafe.Sizeof函數(shù)返回操作數(shù)在內(nèi)存中的字節(jié)大小,參數(shù)可以是任意類(lèi)型的表達(dá)式,但是它并不會(huì)對(duì)表達(dá)式進(jìn)行求值。一個(gè)Sizeof函數(shù)調(diào)用是一個(gè)對(duì)應(yīng)uintptr類(lèi)型的常量表達(dá)式,因此返回的結(jié)果可以用作數(shù)組類(lèi)型的長(zhǎng)度大小,或者用作計(jì)算其他的常量。
import "unsafe"
fmt.Println(unsafe.Sizeof(float64(0))) // "8"
Sizeof函數(shù)返回的大小只包括數(shù)據(jù)結(jié)構(gòu)中固定的部分,例如字符串對(duì)應(yīng)結(jié)構(gòu)體中的指針和字符串長(zhǎng)度部分,但是并不包含指針指向的字符串的內(nèi)容。Go語(yǔ)言中非聚合類(lèi)型通常有一個(gè)固定的大小,盡管在不同工具鏈下生成的實(shí)際大小可能會(huì)有所不同??紤]到可移植性,引用類(lèi)型或包含引用類(lèi)型的大小在32位平臺(tái)上是4個(gè)字節(jié),在64位平臺(tái)上是8個(gè)字節(jié)。
計(jì)算機(jī)在加載和保存數(shù)據(jù)時(shí),如果內(nèi)存地址合理地對(duì)齊的將會(huì)更有效率。例如2字節(jié)大小的int16類(lèi)型的變量地址應(yīng)該是偶數(shù),一個(gè)4字節(jié)大小的rune類(lèi)型變量的地址應(yīng)該是4的倍數(shù),一個(gè)8字節(jié)大小的float64、uint64或64-bit指針類(lèi)型變量的地址應(yīng)該是8字節(jié)對(duì)齊的。但是對(duì)于再大的地址對(duì)齊倍數(shù)則是不需要的,即使是complex128等較大的數(shù)據(jù)類(lèi)型最多也只是8字節(jié)對(duì)齊。
由于地址對(duì)齊這個(gè)因素,一個(gè)聚合類(lèi)型(結(jié)構(gòu)體或數(shù)組)的大小至少是所有字段或元素大小的總和,或者更大因?yàn)榭赡艽嬖趦?nèi)存空洞。內(nèi)存空洞是編譯器自動(dòng)添加的沒(méi)有被使用的內(nèi)存空間,用于保證后面每個(gè)字段或元素的地址相對(duì)于結(jié)構(gòu)或數(shù)組的開(kāi)始地址能夠合理地對(duì)齊(譯注:內(nèi)存空洞可能會(huì)存在一些隨機(jī)數(shù)據(jù),可能會(huì)對(duì)用unsafe包直接操作內(nèi)存的處理產(chǎn)生影響)。
類(lèi)型 | 大小 |
---|---|
bool
|
1個(gè)字節(jié) |
intN, uintN, floatN, complexN
|
N/8個(gè)字節(jié)(例如float64是8個(gè)字節(jié)) |
int, uint, uintptr
|
1個(gè)機(jī)器字 |
*T
|
1個(gè)機(jī)器字 |
string
|
2個(gè)機(jī)器字(data、len) |
[]T
|
3個(gè)機(jī)器字(data、len、cap) |
map
|
1個(gè)機(jī)器字 |
func
|
1個(gè)機(jī)器字 |
chan
|
1個(gè)機(jī)器字 |
interface
|
2個(gè)機(jī)器字(type、value) |
Go語(yǔ)言的規(guī)范并沒(méi)有要求一個(gè)字段的聲明順序和內(nèi)存中的順序是一致的,所以理論上一個(gè)編譯器可以隨意地重新排列每個(gè)字段的內(nèi)存位置,雖然在寫(xiě)作本書(shū)的時(shí)候編譯器還沒(méi)有這么做。下面的三個(gè)結(jié)構(gòu)體雖然有著相同的字段,但是第一種寫(xiě)法比另外的兩個(gè)需要多50%的內(nèi)存。
// 64-bit 32-bit
struct{ bool; float64; int16 } // 3 words 4words
struct{ float64; int16; bool } // 2 words 3words
struct{ bool; int16; float64 } // 2 words 3words
關(guān)于內(nèi)存地址對(duì)齊算法的細(xì)節(jié)超出了本書(shū)的范圍,也不是每一個(gè)結(jié)構(gòu)體都需要擔(dān)心這個(gè)問(wèn)題,不過(guò)有效的包裝可以使數(shù)據(jù)結(jié)構(gòu)更加緊湊(譯注:未來(lái)的Go語(yǔ)言編譯器應(yīng)該會(huì)默認(rèn)優(yōu)化結(jié)構(gòu)體的順序,當(dāng)然應(yīng)該也能夠指定具體的內(nèi)存布局,相同討論請(qǐng)參考 Issue10014 ),內(nèi)存使用率和性能都可能會(huì)受益。
unsafe.Alignof
函數(shù)返回對(duì)應(yīng)參數(shù)的類(lèi)型需要對(duì)齊的倍數(shù)。和 Sizeof 類(lèi)似, Alignof 也是返回一個(gè)常量表達(dá)式,對(duì)應(yīng)一個(gè)常量。通常情況下布爾和數(shù)字類(lèi)型需要對(duì)齊到它們本身的大?。ㄗ疃?個(gè)字節(jié)),其它的類(lèi)型對(duì)齊到機(jī)器字大小。
unsafe.Offsetof
函數(shù)的參數(shù)必須是一個(gè)字段 x.f
,然后返回 f
字段相對(duì)于 x
起始地址的偏移量,包括可能的空洞。
圖 13.1 顯示了一個(gè)結(jié)構(gòu)體變量 x 以及其在32位和64位機(jī)器上的典型的內(nèi)存?;疑珔^(qū)域是空洞。
var x struct {
a bool
b int16
c []int
}
下面顯示了對(duì)x和它的三個(gè)字段調(diào)用unsafe包相關(guān)函數(shù)的計(jì)算結(jié)果:
32位系統(tǒng):
Sizeof(x) = 16 Alignof(x) = 4
Sizeof(x.a) = 1 Alignof(x.a) = 1 Offsetof(x.a) = 0
Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2
Sizeof(x.c) = 12 Alignof(x.c) = 4 Offsetof(x.c) = 4
64位系統(tǒng):
Sizeof(x) = 32 Alignof(x) = 8
Sizeof(x.a) = 1 Alignof(x.a) = 1 Offsetof(x.a) = 0
Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2
Sizeof(x.c) = 24 Alignof(x.c) = 8 Offsetof(x.c) = 8
雖然這幾個(gè)函數(shù)在不安全的unsafe包,但是這幾個(gè)函數(shù)調(diào)用并不是真的不安全,特別在需要優(yōu)化內(nèi)存空間時(shí)它們返回的結(jié)果對(duì)于理解原生的內(nèi)存布局很有幫助。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: