unsafe.Sizeof
, Alignof
, and Offsetof
The unsafe.Sizeof
function reports the size in bytes
of the representation of its operand,
which may be an expression of any type; the expression is not
evaluated.
A call to Sizeof
is a constant expression of type
uintptr
,
so the result may be used as the dimension of an array
type, or to compute other constants.
import "unsafe" fmt.Println(unsafe.Sizeof(float64(0))) // "8"
Sizeof
reports only the size of the fixed part of each data
structure, like the pointer and length of a string, but not
indirect parts like the contents of the string.
Typical sizes for all non-aggregate Go types are shown
below, though the exact sizes may vary by toolchain.
For portability, we’ve given the sizes of reference types (or types
containing references) in terms of words, where a word is 4 bytes on a
32-bit platform and 8 bytes on a 64-bit platform.
Computers load and store values from memory most efficiently when
those values are properly aligned. For example, the address of a
value of a two-byte type such as int16
should be an even number, the
address of a four-byte value such as a rune
should be a multiple of
four, and the address of an eight-byte value such as a float64
,
uint64
, or 64-bit pointer should be a multiple of eight. Alignment
requirements of higher multiples are unusual, even for larger data
types such as complex128
.
For this reason, the size of a value of an aggregate type (a struct or array) is at least the sum of the sizes of its fields or elements but may be greater due to the presence of “holes.” Holes are unused spaces added by the compiler to ensure that the following field or element is properly aligned relative to the start of the struct or array.
Type | Size |
bool |
1 byte |
int N , uint N , float N , complex N |
N / 8 bytes (for example, float64 is 8 bytes) |
int , uint , uintptr |
1 word |
*T |
1 word |
string |
2 words (data, len) |
[]T |
3 words (data, len, cap) |
map |
1 word |
func |
1 word |
chan |
1 word |
interface |
2 words (type, value) |
The language specification does not guarantee that the order in which fields are declared is the order in which they are laid out in memory, so in theory a compiler is free to rearrange them, although as we write this, none do. If the types of a struct’s fields are of different sizes, it may be more space-efficient to declare the fields in an order that packs them as tightly as possible. The three structs below have the same fields, but the first requires up to 50% more memory than the other two:
// 64-bit 32-bit struct{ bool; float64; int16 } // 3 words 4 words struct{ float64; int16; bool } // 2 words 3 words struct{ bool; int16; float64 } // 2 words 3 words
The details of the alignment algorithm are beyond the scope of this book, and it’s certainly not worth worrying about every struct, but efficient packing may make frequently allocated data structures more compact and therefore faster.
The unsafe.Alignof
function reports the required alignment of
its argument’s type.
Like Sizeof
, it may be applied to an expression of any type, and it
yields a constant. Typically, boolean and numeric types are aligned to
their size (up to a maximum of 8 bytes) and all other types are
word-aligned.
The unsafe.Offsetof
function, whose operand must be a field
selector x.f
, computes the offset of field f
relative to the
start of its enclosing struct x
, accounting for holes, if any.
Figure 13.1 shows a struct variable x
and its memory layout
on typical 32- and 64-bit Go implementations. The gray regions are holes.
var x struct { a bool b int16 c []int }
The table below shows the results of applying the three unsafe
functions to x
itself and to each of its three fields:
Typical 32-bit platform: 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 Typical 64-bit platform: 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
Despite their names, these functions are not in fact unsafe, and they may be helpful for understanding the layout of raw memory in a program when optimizing for space.