草庐IT

go - 内联和输出二进制大小

coder 2024-07-09 原文

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"

可执行文件的大小 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

为什么?

Go 版本 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)值保存一个副本,并且函数调用不是内联的,但是当函数值被隐式包装在 interface{} 值中时被使用时,它是内联的(重复的)。每一次,就是一万五千次!所以基本上 Cell() 函数体被包含了 15.000 次。现在它很大,这就是生成的二进制文件有 30 MB 的原因。

启用内联时

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

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

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

有关go - 内联和输出二进制大小的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  4. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  5. ruby - 将 spawn() 的标准输出/标准错误重定向到 Ruby 中的字符串 - 2

    我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])

  6. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  7. Ruby - 如何将消息长度表示为 2 个二进制字节 - 2

    我正在使用Ruby,我正在与一个网络端点通信,该端点在发送消息本身之前需要格式化“header”。header中的第一个字段必须是消息长度,它被定义为网络字节顺序中的2二进制字节消息长度。比如我的消息长度是1024。如何将1024表示为二进制双字节? 最佳答案 Ruby(以及Perl和Python等)中字节整理的标准工具是pack和unpack。ruby的packisinArray.您的长度应该是两个字节长,并且按网络字节顺序排列,这听起来像是n格式说明符的工作:n|Integer|16-bitunsigned,network(bi

  8. HBase Region 简介和建议数量&大小 - 2

    Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile

  9. ruby - Ruby 是否使用 $stdout 来写入 puts 和 return 的输出? - 2

    我想知道Ruby用来在命令行打印这些东西的输出流:irb(main):001:0>a="test"=>"test"irb(main):002:0>putsatest=>nilirb(main):003:0>a=>"test"$stdout是否用于irb(main):002:0>和irb(main):003:0>?而且,在这两次调用之间,$stdout的值是否有任何变化?另外,有人能告诉我打印/写入这些内容的Ruby源代码吗? 最佳答案 是的。而且很容易向自己测试/证明。在命令行试试这个:ruby-e'puts"foo"'>test.

  10. ruby-on-rails - 无法在 Rails 助手中捕获 block 的输出 - 2

    我在使用自定义RailsFormBuilder时遇到了问题,从昨天晚上开始我就发疯了。基本上我想对我的构建器方法之一有一个可选block,以便我可以在我的主要content_tag中显示其他内容。:defform_field(method,&block)content_tag(:div,class:'field')doconcatlabel(method,"Label#{method}")concattext_field(method)capture(&block)ifblock_given?endend当我在我的一个Slim模板中调用该方法时,如下所示:=f.form_field:e

随机推荐