Подтвердить что ты не робот

Причина огромного размера скомпилированного исполняемого файла Go

Я выполнил программу hello world Go, которая сгенерировала собственный исполняемый файл на моей Linux-машине. Но я был удивлен, увидев размер простой программы Hello world Go, это было 1.9MB!

Почему это так, что исполняемый файл такой простой программы в Go настолько огромен?

4b9b3361

Ответ 1

Этот точный вопрос появляется в официальном FAQ: Почему моя тривиальная программа такая большая двоичная? p >

Цитирование ответа:

Линкеры в цепочке инструментов gc (5l, 6l и 8l) выполняют статические ссылки. Таким образом, все бинарные файлы Go включают в себя время выполнения Go вместе с информацией типа времени выполнения, необходимой для поддержки проверок динамического типа, отражения и даже трассировки стека паники.

Простая программа C "hello, world", скомпилированная и связанная статически с использованием gcc в Linux, составляет около 750 kB, включая реализацию printf. Эквивалентная программа Go с использованием fmt.Printf составляет около 1,9 МБ, но включает более мощную поддержку и информацию о времени выполнения.

Таким образом, собственный исполняемый файл вашего Hello World составляет 1,9 МБ, поскольку он содержит среду выполнения, которая предоставляет сборку мусора, отражение и многие другие функции (которые ваша программа может не использовать, но там). И реализация пакета fmt, который вы использовали для печати текста "Hello World" (плюс его зависимости).

Теперь попробуйте следующее: добавьте еще одну строку fmt.Println("Hello World! Again") в свою программу и скомпилируйте ее снова. Результат не будет 2x 1,9 МБ, но все равно всего 1,9 МБ! Да, потому что все используемые библиотеки (fmt и его зависимости) и среда выполнения уже добавлены в исполняемый файл (и поэтому для печати второго текста, который вы только что добавили, будет добавлено только несколько байт).

Ответ 2

Обратите внимание, что проблема двоичного размера отслеживается проблемой 6853 в golang/go.

Например, совершить a26c01a (для Go 1.4) сократить мир привет на 70kB:

потому что мы не записываем эти имена в таблицу символов.

Учитывая компилятор, ассемблер, компоновщик и среда выполнения для 1.5 будут полностью в Go, вы можете ожидать дальнейшей оптимизации.

Ответ 3

Рассмотрим следующую программу:

package main

import "fmt"

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

Если я построю это на моей машине AMD64 (Go 1.9), вот так:

$ go build
$ ls -la helloworld
-rwxr-xr-x 1 janf group 2029206 Sep 11 16:58 helloworld

Я получаю двоичный файл размером около 2 МБ.

Причина этого (что объясняется в других ответах) заключается в том, что мы используем пакет "fmt", который довольно велик, но двоичный файл также не был удален, а это означает, что таблица символов все еще существует. Если мы вместо этого попросим компилятор удалить бинарный файл, он станет намного меньше:

$ go build -ldflags "-s -w"
$ ls -la helloworld
-rwxr-xr-x 1 janf group 1323616 Sep 11 17:01 helloworld

Однако, если мы перепишем программу для использования встроенной функции print, вместо fmt.Println, выполните следующие действия:

package main

func main() {
    print("Hello World!\n")
}

И затем скомпилируйте его:

$ go build -ldflags "-s -w"
$ ls -la helloworld
-rwxr-xr-x 1 janf group 714176 Sep 11 17:06 helloworld

В итоге мы получим еще меньшую двоичную. Это настолько мало, что мы можем получить его, не прибегая к трюкам, таким как UPX-упаковка, поэтому накладные расходы Go-runtime составляют около 700 Kb.