Go structures use a technique called alignment, which consists of adding one or more bytes to data structures to make it fit into memory addresses better. Consider the following data structure:
struct {
a string
b bool
c []byte
}
With 64-bit architecture calling unsafe.Sizeof on this structure, this will give us an unexpected result. What we are expecting is the following:
- 16 bytes from the string; 8 for the pointer to the first element, and 8 for the length
- 1 byte for the Boolean
- 24 for the slice; 8 for the address, 8 for the length, and 8 for capacity
The total should be 41, but the function returns 48. This happens because the compiler inserts extra bytes after the Boolean, to reach 8 bytes (64 bits) and optimize the operation for the CPU. The structure could be represented in memory as follows:
We can see that the Boolean variable takes 1 bit, and that there are 7 extra bits added by the compiler. This is very helpful because it avoids the other variables that are store, half in one memory slot and half in another. This would require two reads and two writes per operation, with a significant drop in performance.
If two or more fields are small enough to fit in one slot of 64 bits, they will be stored sequentially. We can see this with the following example:
struct {
a, b bool
c rune
d byte
e string
}
This structure translates into the following memory representation on a 64-bit architecture:
We can clearly see that both the Boolean variables, the rune and the byte, are in the same memory address, and a byte of padding is added to align the last field.