package main
type TreeCell struct {
Tabs func() *string
}
func Cell() *string {
s:= ""
return &s
}
func Table(Line *[]TreeCell) {
if Line != nil {
Num["rtt"] = Line
}
}
var (
Num map[string]*[]TreeCell
)
func main() {
Table(&[]TreeCell{
TreeCell{Tabs: Cell},
TreeCell{Tabs: Cell},
...repeat 15000 times
TreeCell{Tabs: Cell},
})
}
go build -a -v -gcflags "-N -l" -ldflags "-s -w"
Size of executable file 1,9Mb
__text 1459891 16781312
__rodata 158107 18241216
Total 1951521
if I change the func() *string
to the interface{}
type TreeCell struct {
Tabs interface{}
}
then size of executable file 32Mb
__text 1864389 16781312
__rodata 30375699 18645728
Total 32698219
Why?
Go version 1.9.2
The size of an interface{}
variable is 8 or 16 bytes (depending on the architecture being 32 or 64 bit), and the size of a function variable is either 4 or 8 bytes. So there is only a 2 multiplication which would not explain the big difference in the output binary (15.000 * 8 bytes is only 120 KB).
What you experience is the result of different inlining compiler optimization. The function Cell()
is very simple and is eligible for inlining.
If we include the -gcflags '-N -l'
params like in your example (these flags tell the compiler to disable inlining), then references to Cell
are not inlined, so using func() *string
will only use a 4-byte function pointer.
Using interface{}
however will result in inlining Cell
values. Interface values hold a copy, and the function call is not inlined, but when the function value is used when implicitly wrapped in interface{}
values, it is inlined (duplicated). In each time, that is 15.000 times! So basically the Cell()
function body is included 15.000 times. Now that's big, that is what makes the resulting binary 30 MB.
If we exclude the -gcflags '-N -l'
params, it's actually the opposite: the compiled binary is about 2 MB when using interface{}
, and it's about 30 MB when using func () *string
.
This time when using the Cell
function value in the composite literal for initializing the TreeCell.Tabs
field, the compiler will inline the Cell()
function in all 15.000 times! When using interface{}
, the function bodies will not be inlined however. Not sure why, a possible explanation is that it is also inlined in case of interface{}
, and since interface values are immutable, the same value is used 15.000 times.