mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2026-01-16 12:17:13 +08:00
回到简体
This commit is contained in:
@@ -1,33 +1,33 @@
|
||||
## 13.1. unsafe.Sizeof, Alignof 和 Offsetof
|
||||
|
||||
unsafe.Sizeof函數返迴操作數在內存中的字節大小,參數可以是任意類型的表達式,但是它併不會對表達式進行求值。一個Sizeof函數調用是一個對應uintptr類型的常量表達式,因此返迴的結果可以用作數組類型的長度大小,或者用作計算其他的常量。
|
||||
unsafe.Sizeof函数返回操作数在内存中的字节大小,参数可以是任意类型的表达式,但是它并不会对表达式进行求值。一个Sizeof函数调用是一个对应uintptr类型的常量表达式,因此返回的结果可以用作数组类型的长度大小,或者用作计算其他的常量。
|
||||
|
||||
```Go
|
||||
import "unsafe"
|
||||
fmt.Println(unsafe.Sizeof(float64(0))) // "8"
|
||||
```
|
||||
|
||||
Sizeof函數返迴的大小隻包括數據結構中固定的部分,例如字符串對應結構體中的指針和字符串長度部分,但是併不包含指針指向的字符串的內容。Go語言中非聚合類型通常有一個固定的大小,盡管在不同工具鏈下生成的實際大小可能會有所不同。考慮到可移植性,引用類型或包含引用類型的大小在32位平台上是4個字節,在64位平台上是8個字節。
|
||||
Sizeof函数返回的大小只包括数据结构中固定的部分,例如字符串对应结构体中的指针和字符串长度部分,但是并不包含指针指向的字符串的内容。Go语言中非聚合类型通常有一个固定的大小,尽管在不同工具链下生成的实际大小可能会有所不同。考虑到可移植性,引用类型或包含引用类型的大小在32位平台上是4个字节,在64位平台上是8个字节。
|
||||
|
||||
計算機在加載和保存數據時,如果內存地址合理地對齊的將會更有效率。例如2字節大小的int16類型的變量地址應該是偶數,一個4字節大小的rune類型變量的地址應該是4的倍數,一個8字節大小的float64、uint64或64-bit指針類型變量的地址應該是8字節對齊的。但是對於再大的地址對齊倍數則是不需要的,卽使是complex128等較大的數據類型最多也隻是8字節對齊。
|
||||
计算机在加载和保存数据时,如果内存地址合理地对齐的将会更有效率。例如2字节大小的int16类型的变量地址应该是偶数,一个4字节大小的rune类型变量的地址应该是4的倍数,一个8字节大小的float64、uint64或64-bit指针类型变量的地址应该是8字节对齐的。但是对于再大的地址对齐倍数则是不需要的,即使是complex128等较大的数据类型最多也只是8字节对齐。
|
||||
|
||||
由於地址對齊這個因素,一個聚合類型(結構體或數組)的大小至少是所有字段或元素大小的總和,或者更大因爲可能存在內存空洞。內存空洞是編譯器自動添加的沒有被使用的內存空間,用於保證後面每個字段或元素的地址相對於結構或數組的開始地址能夠合理地對齊(譯註:內存空洞可能會存在一些隨機數據,可能會對用unsafe包直接操作內存的處理産生影響)。
|
||||
由于地址对齐这个因素,一个聚合类型(结构体或数组)的大小至少是所有字段或元素大小的总和,或者更大因为可能存在内存空洞。内存空洞是编译器自动添加的没有被使用的内存空间,用于保证后面每个字段或元素的地址相对于结构或数组的开始地址能够合理地对齐(译注:内存空洞可能会存在一些随机数据,可能会对用unsafe包直接操作内存的处理产生影响)。
|
||||
|
||||
|
||||
類型 | 大小
|
||||
类型 | 大小
|
||||
----------------------------- | ----
|
||||
bool | 1個字節
|
||||
intN, uintN, floatN, complexN | N/8個字節(例如float64是8個字節)
|
||||
int, uint, uintptr | 1個機器字
|
||||
*T | 1個機器字
|
||||
string | 2個機器字(data,len)
|
||||
[]T | 3個機器字(data,len,cap)
|
||||
map | 1個機器字
|
||||
func | 1個機器字
|
||||
chan | 1個機器字
|
||||
interface | 2個機器字(type,value)
|
||||
bool | 1个字节
|
||||
intN, uintN, floatN, complexN | N/8个字节(例如float64是8个字节)
|
||||
int, uint, uintptr | 1个机器字
|
||||
*T | 1个机器字
|
||||
string | 2个机器字(data,len)
|
||||
[]T | 3个机器字(data,len,cap)
|
||||
map | 1个机器字
|
||||
func | 1个机器字
|
||||
chan | 1个机器字
|
||||
interface | 2个机器字(type,value)
|
||||
|
||||
Go語言的規范併沒有要求一個字段的聲明順序和內存中的順序是一致的,所以理論上一個編譯器可以隨意地重新排列每個字段的內存位置,隨然在寫作本書的時候編譯器還沒有這麽做。下面的三個結構體雖然有着相同的字段,但是第一種寫法比另外的兩個需要多50%的內存。
|
||||
Go语言的规范并没有要求一个字段的声明顺序和内存中的顺序是一致的,所以理论上一个编译器可以随意地重新排列每个字段的内存位置,随然在写作本书的时候编译器还没有这么做。下面的三个结构体虽然有着相同的字段,但是第一种写法比另外的两个需要多50%的内存。
|
||||
|
||||
```Go
|
||||
// 64-bit 32-bit
|
||||
@@ -36,13 +36,13 @@ struct{ float64; int16; bool } // 2 words 3words
|
||||
struct{ bool; int16; float64 } // 2 words 3words
|
||||
```
|
||||
|
||||
關於內存地址對齊算法的細節超出了本書的范圍,也不是每一個結構體都需要擔心這個問題,不過有效的包裝可以使數據結構更加緊湊(譯註:未來的Go語言編譯器應該會默認優化結構體的順序,當然用於應該也能夠指定具體的內存布局,相同討論請參考 [Issue10014](https://github.com/golang/go/issues/10014) ),內存使用率和性能都可能會受益。
|
||||
关于内存地址对齐算法的细节超出了本书的范围,也不是每一个结构体都需要担心这个问题,不过有效的包装可以使数据结构更加紧凑(译注:未来的Go语言编译器应该会默认优化结构体的顺序,当然用于应该也能够指定具体的内存布局,相同讨论请参考 [Issue10014](https://github.com/golang/go/issues/10014) ),内存使用率和性能都可能会受益。
|
||||
|
||||
`unsafe.Alignof` 函數返迴對應參數的類型需要對齊的倍數. 和 Sizeof 類似, Alignof 也是返迴一個常量表達式, 對應一個常量. 通常情況下布爾和數字類型需要對齊到它們本身的大小(最多8個字節), 其它的類型對齊到機器字大小.
|
||||
`unsafe.Alignof` 函数返回对应参数的类型需要对齐的倍数. 和 Sizeof 类似, Alignof 也是返回一个常量表达式, 对应一个常量. 通常情况下布尔和数字类型需要对齐到它们本身的大小(最多8个字节), 其它的类型对齐到机器字大小.
|
||||
|
||||
`unsafe.Offsetof` 函數的參數必須是一個字段 `x.f`, 然後返迴 `f` 字段相對於 `x` 起始地址的偏移量, 包括可能的空洞.
|
||||
`unsafe.Offsetof` 函数的参数必须是一个字段 `x.f`, 然后返回 `f` 字段相对于 `x` 起始地址的偏移量, 包括可能的空洞.
|
||||
|
||||
圖 13.1 顯示了一個結構體變量 x 以及其在32位和64位機器上的典型的內存. 灰色區域是空洞.
|
||||
图 13.1 显示了一个结构体变量 x 以及其在32位和64位机器上的典型的内存. 灰色区域是空洞.
|
||||
|
||||
```Go
|
||||
var x struct {
|
||||
@@ -52,11 +52,11 @@ var x struct {
|
||||
}
|
||||
```
|
||||
|
||||
下面顯示了對x和它的三個字段調用unsafe包相關函數的計算結果:
|
||||
下面显示了对x和它的三个字段调用unsafe包相关函数的计算结果:
|
||||
|
||||

|
||||
|
||||
32位繫統:
|
||||
32位系统:
|
||||
|
||||
```
|
||||
Sizeof(x) = 16 Alignof(x) = 4
|
||||
@@ -65,7 +65,7 @@ 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位繫統:
|
||||
64位系统:
|
||||
|
||||
```
|
||||
Sizeof(x) = 32 Alignof(x) = 8
|
||||
@@ -74,5 +74,5 @@ Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2
|
||||
Sizeof(x.c) = 24 Alignof(x.c) = 8 Offsetof(x.c) = 8
|
||||
```
|
||||
|
||||
雖然這幾個函數在不安全的unsafe包,但是這幾個函數調用併不是眞的不安全,特别在需要優化內存空間時它們返迴的結果對於理解原生的內存布局很有幫助。
|
||||
虽然这几个函数在不安全的unsafe包,但是这几个函数调用并不是真的不安全,特别在需要优化内存空间时它们返回的结果对于理解原生的内存布局很有帮助。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user