如何减少编译文件的大小?

时间:2010-10-05 07:29:49

标签: go

让我们比较c和go: Hello_world.c:

#include<stdio.h>
int main(){
    printf("Hello world!");
}

Hello_world.go:

package main
import "fmt"
func main(){
    fmt.Printf("Hello world!")
}

编译两者:

$gcc Hello_world.c -o Hello_c 
$8g Hello_world.go -o Hello_go.8
$8l Hello_go.8 -o Hello_go

和......它是什么?

$ls -ls
... 5,4K 2010-10-05 11:09 Hello_c
... 991K 2010-10-05 11:17 Hello_go

关于1Mb Hello world。你在跟我开玩笑吗? 我做错了什么?

(剥离Hello_go - &gt;仅限893K)

12 个答案:

答案 0 :(得分:68)

如果您使用的是基于Unix的系统(例如Linux或Mac OSX),您可以尝试通过使用-w标志构建它来删除可执行文件中包含的调试信息:

go build -ldflags "-w" prog.go

文件大小显着减少。

有关详细信息,请访问GDB的页面:http://golang.org/doc/gdb

答案 1 :(得分:35)

2016答案:

1。使用Go 1.7

2。使用go build -ldflags "-s -w"

进行编译
➜ ls -lh hello
-rwxr-xr-x 1 oneofone oneofone 976K May 26 20:49 hello*

3。然后使用upx,自1.6以来不再需要goupx

➜ ls -lh hello
-rwxr-xr-x 1 oneofone oneofone 367K May 26 20:49 hello*

答案 2 :(得分:26)

文件较大是一个问题吗?我不知道Go但我会假设它静态地链接了一些运行时库,这不是C程序的情况。但是一旦你的程序变大,可能就没什么可担心的了。

如上所述here,静态链接Go运行时是默认值。该页面还告诉您如何设置动态链接。

答案 3 :(得分:21)

Go二进制文件很大,因为它们是静态链接的(除了使用cgo的库绑定)。尝试静态链接C程序,你会看到它增长到相当的大小。

如果这对你来说真的是个问题(我很难相信),你可以用gccgo编译并动态链接。

答案 4 :(得分:17)

你应该得到goupx,它会&#34;修复&#34; Golang ELF可执行文件与upx一起使用。在某些情况下,~16MB >> ~3MB我已经有大约78%的文件缩小了。

压缩比通常趋于25%,所以值得一试:

$ go get github.com/pwaller/goupx
$ go build -o filename
$ goupx filename

&GT;&GT;

2014/12/25 10:10:54 File fixed!

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
  16271132 ->   3647116   22.41%  linux/ElfAMD   filename                            

Packed 1 file.

EXTRA:-s标记(条带)可以进一步缩小bin文件goupx -s filename

答案 5 :(得分:10)

更紧凑的hello-world示例:

package main

func main() {
  print("Hello world!")
}

我们正在使用大fmt个大包,并显着减少了二进制文件:

  $ go build hello.go
  $ ls -lh hello
  ... 259K ... hello2
  $ strip hello
  $ ls -lh hello
  ... 162K ... hello2

不像C那么紧凑,但是用K而不是M测量:)好吧,这不是一般的方式只是显示一些优化大小的方法:使用 strip 并尝试使用最小包。无论如何Go并不是制作小尺寸二进制文件的语言。

答案 6 :(得分:7)

创建一个名为main.go的文件, 让我们试试简单的hello world程序。

package main

import "fmt"

func main(){
    fmt.Println("Hello World!")
}

我使用的是版本1.9.1

$ go version
 go version go1.9.1 linux/amd64

使用标准go build命令进行编译。

$ go build main.go
$ ls -lh
-rwxr-xr-x-x 1 nil nil 1.8M Oct 27 07:47 main

让我们使用go build再次编译,但如上所述使用ldflags

$ go build -ldflags "-s -w" main.go
$ ls -lh
-rwxr-xr-x-x 1 nil nil 1.2M Oct 27 08:15 main

文件大小减少了30%。

现在,让我们使用gccgo

$ go version
 go version go1.8.1 gccgo (GCC) 7.2.0 linux/amd64

建立gccgo

$ go build main.go
$ ls -lh
-rwxr-xr-x 1 nil nil 34K Oct 27 12:18 main

二进制大小减少了近100%。 让我们再次尝试使用main.go构建gccgo但使用构建标记

$ go build -gccgoflags "-s -w" main.go
-rwxr-xr-x 1 nil nil 23K Oct 27 13:02 main

警告: 由于gccgo二进制文件是动态链接的。 如果你有一个非常大的二进制文件,你用gccgo编译时的二进制文件不会减少100%,但它的大小会减少相当大的数量。

与gc相比,gccgo编译代码的速度较慢,但​​支持更强大的优化,因此gccgo构建的CPU绑定程序通常运行得更快。多年来在GCC中实现的所有优化都是可用的,包括内联,循环优化,向量化,指令调度等。虽然它并不总能产生更好的代码,但在某些情况下,使用gccgo编译的程序运行速度可提高30%。

GCC 7版本预计将包括Go 1.8用户库的完整实现。与早期版本一样,Go 1.8运行时未完全合并,但Go程序不应该看到它。

<强>优点:

  1. 缩小尺寸
  2. 优化。
  3. <强>缺点

    1. 无法使用最新版本的go
    2. 您可以查看herehere

答案 7 :(得分:3)

您可以看看我在这个问题上的小型研究: https://github.com/xaionaro/documentation/blob/master/golang/reduce-binary-size.md

它逐步说明了如何将2MiB hello-world静态二进制样本减少为15KiB静态二进制或10KiB动态二进制。当然有很多限制。

答案 8 :(得分:1)

二进制文件默认包含垃圾收集器,管理go例程的schedulding系统以及您导入的所有库。

结果是最小尺寸约为1 Mb。

答案 9 :(得分:1)

从Go 1.8开始,您还可以使用新的插件系统将二进制文件拆分为类似于共享库的内容。对于此版本,它仅适用于Linux,但将来可能会支持其他平台。

https://tip.golang.org/pkg/plugin/

答案 10 :(得分:1)

2018回答下一个Go 1.11,as tweetedBrad Fitzpatrick(2018年6月中旬):

  

从几分钟前开始,#golang ELF二进制文件中的DWARF部分现在已被压缩,因此尖端二进制文件现在小于Go 1.10,即使所有额外的调试内容都在尖端。

https://pbs.twimg.com/media/DfwkBaqUEAAb8-Q.jpg:large

比照。 Golang issue 11799

  

压缩我们的调试信息可能会提供一个重要的,廉价的文件大小胜利。

commit 594eae5

中查看详情
  

cmd / link:压缩ELF二进制文件中的DWARF部分

     

最棘手的部分是二进制布局代码(blk,elfshbits和其他各种东西)假定符号和部分的文件位置及其虚拟地址之间存在恒定的偏移。

     

当然,压缩打破了这种不断的偏移   但是我们需要在压缩之前为所有内容分配虚拟地址   在压缩之前解决重定位问题。

     

因此,压缩需要根据压缩大小重新计算DWARF部分和符号的“地址”。
  幸运的是,这些都在文件的末尾,所以这不会扰乱任何其他部分或符号。 (当然,还有一些令人惊讶的代码假定DWARF段最后一个,那么还有一个地方呢?)

name        old exe-bytes   new exe-bytes   delta
HelloSize      1.60MB ± 0%     1.05MB ± 0%  -34.39%  (p=0.000 n=30+30)
CmdGoSize      16.5MB ± 0%     11.3MB ± 0%  -31.76%  (p=0.000 n=30+30)
[Geo mean]     5.14MB          3.44MB       -33.08%

Rob Pike mentions

  

这仅对使用ELF的机器有帮助   二进制文件仍然太大,而且还在增长。

布拉德回答说:

  

至少它是什么。即将变得更糟   停止了一次释放的出血。

Reasons:调试信息,但也为GC注册地图,让任何指令成为保存点。

答案 11 :(得分:1)

默认情况下,gcc动态链接并静态链接。 但是,如果您静态链接C代码,则可能会得到一个更大的二进制文件。

就我而言:

  • go x64(1.10.3)-生成的二进制文件大小为1214208字节
  • gcc x64(6.2.0)-生成的二进制文件大小为1421312字节

两个二进制文件都是静态链接的,并且没有debug_info。


    <?php

    namespace App\Http\Controllers\Admin;

    use Illuminate\Http\Request;
    use App\Http\Controllers\Controller;
    use App\Http\Controllers\Admin\AdminBaseController;
    use Youtube;

    class LessonController extends AdminBaseController
    {
        function save(Request $request)
        {
            $video = Youtube::upload($request->file('video')->getPathName(), [
            'title'       => 'My Video',
            'description' => 'This video is uploaded through API.',
             'tags'        => ['api', 'youtube'],
            ]);

            return $video->getVideoId();
        }
    }