unsafe.Sizeof 函数
// Sizeof takes an expression x of any type and returns the size in bytes
// of a hypothetical variable v as if v was declared via var v = x.
// The size does not include any memory possibly referenced by x.
// For instance, if x is a slice, Sizeof returns the size of the slice
// descriptor, not the size of the memory referenced by the slice.
// The return value of Sizeof is a Go constant.
func Sizeof(x ArbitraryType) uintptr
翻译:
参数: 任何类型的表达式 x ;
返回: 假想有一个变量 v , 定义 var v = x , 返回 变量 v 的字节大小;返回值是一个常量;
注:返回的字节大小不包括 x 引用的内存;举个栗子,假设 x 是一个切片,Sizeof(x) 返回的是切片这个结构占用的内存大小,不包括切片引用值的占用内存大小。
各类型 Sizeof 大小
类型 | 大小 |
bool | 1个字节 |
intN uintN floatN complexN | N/8个字节(比如 int64是8个字节) |
int uint uintptr | 1个机器字(32位机器4字节,64位机器8字节) |
*T | 1个机器字 |
string | 2个机器字 |
[]T 切片 | 3个机器字 |
map | 1个机器字 |
func | 1个机器字 |
chan | 1个机器字 |
interface | 2个机器字 |
[...]T 数组, strcut 结构体 | 至少是所有字段大小的总和(因为存在 内存对齐) |
认识一下几个特别的类型:
字符串 string
// StringHeader is the runtime representation of a string.
// It cannot be used safely or portably and its representation may
// change in a later release.
// Moreover, the Data field is not sufficient to guarantee the data
// it references will not be garbage collected, so programs must keep
// a separate, correctly typed pointer to the underlying data.
type StringHeader struct {
Data uintptr
Len int
}
StringHeader 是 string 的运行时表示,从源码可以看出,string 实际上是一个由两个字段组成的结构体:
- Data 是一个地址值,指向底层真正存储数据的内存地址;
- Len 表示字符串长度;
因此, Sizeof(string) = Sizeof(uintptr) + Sizeof(int) = 2 个机器字。
切片 slice
// SliceHeader is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may
// change in a later release.
// Moreover, the Data field is not sufficient to guarantee the data
// it references will not be garbage collected, so programs must keep
// a separate, correctly typed pointer to the underlying data.
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
SliceHeader 是 slice 的运行时表示,可以看出,切片是一个由三个字段组成的结构体:
- Data 是一个地址值,指向底层数组;
- Len 表示切片长度;
- Cap 表示切片容量;
因此, Sizeof(slice) = Sizeof(uintptr) + Sizeof(int) + Sizeof(int) = 3 个机器字。
接口 interface
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *rtype
word unsafe.Pointer
}
// nonEmptyInterface is the header for an interface value with methods.
type nonEmptyInterface struct {
// see ../runtime/iface.go:/Itab
itab *struct {
ityp *rtype // static interface type
typ *rtype // dynamic concrete type
hash uint32 // copy of typ.hash
_ [4]byte
fun [100000]unsafe.Pointer // method table
}
word unsafe.Pointer
}
interface 根据 接口是否含有方法 分别使用 nonEmptyInterface 和 emptyInterface 表示。
- 两个结构体中 word 字段都表示 实现该接口的类型的实例指针;
- emptyInterface 里的 typ 是一个结构体指针,rtype 结构体用来描述 类型信息,比如类型大小、对齐方式...等信息;
- nonEmptyInterface 里的 itab 也是一个结构体指针,itab 结构体描述的信息类似于 c++ 里的虚函数表,主要包含 接口自身定义的类型信息、实际对象类型、函数地址列表...等信息;
因此,两种结构都可用以下表达式计算:
Sizeof(interface) = Sizeof(*T) + Sizeof(*T) = 2 个机器字 (unsafe.Pointer 是一个特殊类型的指针,类似于 c 里面的 void*)。