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},
    })
}

去建立-a -v -gcflags“-N -l” -ldflags“-s -w”

可执行文件的大小1,9Mb
__text              1459891   16781312
__rodata             158107   18241216
Total               1951521

如果我将func() *string更改为interface{}
type TreeCell struct {
    Tabs interface{}
}

然后是可执行文件大小32Mb
__text               1864389   16781312
__rodata            30375699   18645728
Total               32698219

为什么?

转到1.9.2版

最佳答案

interface{}变量的大小为8或16个字节(取决于体系结构为32或64位),而函数变量的大小为4或8个字节。因此,只有2倍的乘法不能解释输出二进制文件的巨大差异(15.000 * 8字节仅为120 KB)。

您所经历的是不同的内联编译器优化的结果。函数Cell()非常简单,可以进行内联。

禁用内联时

如果我们像您的示例中那样包含-gcflags '-N -l'参数(这些标志告诉编译器禁用内联),则不内联对Cell的引用,因此使用func() *string将仅使用4字节的函数指针。

但是,使用interface{}将导致内联Cell值。接口值保留一个副本,并且不内联该函数调用,但是当隐式地将其包装在interface{}值中时使用该函数值时,将对其进行内联(重复)。每次就是15.000次!因此,基本上Cell()函数体被包含15.000次。现在很大,这就是生成的二进制文件30 MB的原因。

启用内联时

如果我们排除-gcflags '-N -l'参数,则实际上是相反的:使用interface{}时已编译的二进制文件约为2 MB,而使用func () *string时则约为30 MB。

这次,当使用复合文字中的Cell函数值初始化TreeCell.Tabs字段时,编译器将内联Cell()函数所有15.000次!当使用interface{}时,将不会内联函数体。不知道为什么,一个可能的解释是,在interface{}的情况下,它也是内联的,并且由于接口值是不可变的,因此相同的值被使用了15.000次。

关于go - 内联和输出二进制大小,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47968970/

10-16 12:32