Как уменьшить размер скомпилированного файла? - PullRequest
71 голосов
/ 05 октября 2010

Давайте сравним 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_go -> только 893K)

Ответы [ 10 ]

69 голосов
/ 15 января 2014

Если вы используете систему на основе Unix (например, Linux или Mac OSX), вы можете попробовать удалить отладочную информацию, включенную в исполняемый файл, с помощью флага -w:

go build -ldflags "-w" prog.go

Размеры файлов значительно уменьшены.

Для более подробной информации посетите страницу GDB: http://golang.org/doc/gdb

36 голосов
/ 26 мая 2016

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, goupx больше не нужно, начиная с 1.6.

➜ ls -lh hello
-rwxr-xr-x 1 oneofone oneofone 367K May 26 20:49 hello*
26 голосов
/ 05 октября 2010

Проблема в том, что файл больше?Я не знаю Go, но я бы предположил, что он статически связывает некоторую библиотеку времени выполнения, что не относится к программе на Си.Но, вероятно, не о чем беспокоиться, как только ваша программа станет больше.

Как описано здесь , статическое связывание среды выполнения Go является значением по умолчанию.На этой странице также рассказывается, как настроить динамическое связывание.

22 голосов
/ 05 октября 2010

Двоичные файлы Go большие, потому что они статически связаны (за исключением привязок библиотеки с использованием cgo).Попробуйте статически связать программу на C, и вы увидите, что она увеличится до сопоставимого размера.

Если это действительно проблема для вас (в это мне трудно поверить), вы можете скомпилировать с помощью gccgo и динамически связать.

17 голосов
/ 25 декабря 2014

Вы должны получить goupx , это "исправит" исполняемые файлы Golang ELF для работы с upx. У меня уже есть 78% уменьшение размера файла в некоторых случаях ~16MB >> ~3MB.

Степень сжатия обычно составляет 25%, поэтому стоит попробовать:

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

>>

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

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

Packed 1 file.

ДОПОЛНИТЕЛЬНО: -s флаг (полоса) может сжать файл bin еще больше goupx -s filename

10 голосов
/ 28 февраля 2013

Более компактный пример 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 не является языком для создания крошечных двоичных файлов.

7 голосов
/ 27 октября 2017

создайте файл с именем main.go, давайте попробуем с простой программой hello world.

package main

import "fmt"

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

Я использую версию go 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, будет обычно работать быстрее.Доступны все оптимизации, реализованные в GCC за прошедшие годы, включая встраивание, оптимизацию цикла, векторизацию, планирование команд и многое другое.Хотя это не всегда дает лучший код, в некоторых случаях программы, скомпилированные с помощью gccgo, могут работать на 30% быстрее.

Ожидается, что релизы GCC 7 будут включать полную реализацию пользовательских библиотек Go 1.8.Как и в более ранних выпусках, среда выполнения Go 1.8 объединена не полностью, но это не должно быть видно программам Go.

Плюсы:

  1. Уменьшенный размер
  2. Оптимизировано.

Минусы

  1. Медленно
  2. Невозможно использовать последнюю версию go.

Вы можете увидеть более здесь и здесь .

1 голос
/ 16 июня 2018

2018 ответ на следующий Go 1.11, в твиттере от Брэд Фицпатрик (середина июня 2018 г.):

Начиная с нескольких минут назад, секции DWARF в двоичных файлах #golang ELF теперь сжимаются, поэтому у исполняемых файлов tip теперь меньше, чем в Go 1.10, даже со всеми дополнительными средствами отладки в tip.

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

Cf. Выпуск Голанга 11799 :

Сжатие нашей отладочной информации может дать значительный, дешевый выигрыш в размере файла.

Подробнее в коммит 594eae5

cmd / link: сжатие секций DWARF в двоичных файлах ELF

Самая хитрая часть этого заключается в том, что двоичный код макета (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%

Роб Пайк упоминает :

Это помогает только на машинах, использующих ELF.
Двоичные файлы все еще слишком велики и растут.

Брэд ответил:

По крайней мере, это что-то. Должно было быть намного хуже.
Остановил кровотечение на один выпуск.

Причины : Отладочная информация, но также зарегистрировать карту для GC, чтобы любая инструкция была точкой сохранения.

1 голос
/ 12 января 2017

С Go 1.8 вы также можете использовать новую систему плагинов, чтобы разделить ваш бинарный файл на что-то похожее на разделяемые библиотеки. В этом выпуске он работает только в Linux, но другие платформы, вероятно, будут поддерживаться в будущем.

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

1 голос
/ 31 июля 2013

Двоичный файл по умолчанию содержит сборщик мусора, систему планирования, которая управляет подпрограммами go, и все импортируемые вами библиотеки.

Результат - минимальный размер около 1 МБ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...