So the question you may be asking is when will this happen? When does storing a value in an interface qualify for not needing a memory allocation on the heap? Well, there are a few criteria:
- Zero values, including
0
,nil
, and an empty string""
all qualify. - Any value that is type which is a single byte wide, such as
bool
,int8
, anduint8
. - Any integer type with a value that is in the inclusive range of 0-255.
- In some cases if
T
is subject to an optimization, so too willstruct{a T}
.
In order to produce a more comprehensive dataset for when this behavior could occur, we can run the following command:
docker run -it --rm go-interface-values:latest \
bash -c 'cd ./tests/mem && \
go tool compile -S -wb=false *.go | \
python3 ../../hack/asm2md.py --no-echo'
The output will be a markdown table that indicates the assembly instruction used to store each of the following types, both their zero and non-zero values, in an interface. Some notes about the following information:
-
The table was generated on a linux/amd64 system.
-
The functions to store the zero and non-zero values are the same for both assembly and Go, but I had already written the parser to figure out both, so I kept them in.
-
For some types Go uses the same conversion function for
T
andstruct{a T}
, including:int
,int16
,int32
,int64
uint
,uint16
,uint32
,uint64
float32
,float64
rune
(which has an underlying type ofint32
)string
andstruct{a string}
This means if Go has an optimization for
T
in the above list, the same optimization applies tostruct{a T}
. -
Strangely this behavior does not extend to
struct{a T}
whenT
isbool
,int8
, oruint8
, all single-byte wide values.
Okay, now we know what each function is used when storing specific types in interfaces, but we don't have a clear picture of when those functions malloc and when they do not. Well, I have a clear idea, and you will too once you click to the next page 😃
Next: Overall impact