Raison pour la taille énorme de l'exécutable compilé de Go

j'ai obéi à un programme hello world Go qui a généré des exécutables natifs sur ma machine linux. Mais j'ai été surpris de voir la taille du simple programme Hello world Go, il faisait 1,9 mo !

pourquoi l'exécutable d'un programme aussi simple Dans Go est-il si énorme?

45
demandé sur Karthic Rao 2015-02-18 07:47:10

3 réponses

C'est exactement la question apparaît dans la FAQ officielle: Pourquoi mon programme trivial est-il un si grand binaire?

Citant la réponse:

Les linkers dans la gc, outil de la chaîne (5l,6l et 8l) faire la liaison statique. Tous les binaires de Go incluent donc le temps D'exécution de Go, ainsi que les informations de type de temps d'exécution nécessaires pour supporter les contrôles de type dynamique, la réflexion, et même les traces de pile de temps de panique.

un simple programme C "hello, world" compilé et lié statiquement en utilisant gcc sur Linux est d'environ 750 kB, incluant une implémentation de printf. Un programme Go équivalent utilisant fmt.Printf est d'environ 1.9 Mo, mais cela inclut un support de temps d'exécution plus puissant et des informations de type.

donc l'exécutable natif de votre Hello World est de 1.9 Mo car il contient un runtime qui fournit la collecte des ordures, la réflexion et beaucoup d'autres fonctionnalités (que votre programme pourrait ne pas vraiment l'utiliser, mais il est là). Et la mise en œuvre de l' fmt paquet que vous avez utilisé pour imprimer le "Hello World" texte (et ses dépendances).

maintenant, essayez ce qui suit: ajoutez un autre fmt.Println("Hello World! Again") Tapez votre programme et compilez-le à nouveau. Le résultat ne sera pas 2x 1.9 MB, mais tout de même juste 1.9 MB! Oui, parce que toutes les bibliothèques utilisées (fmt et ses dépendances) et l'exécution sont déjà ajoutés à l'exécutable (et donc juste quelques octets de plus seront ajoutés pour imprimer le 2ème texte qui vous venez d'ajouter).

47
répondu icza 2015-02-18 13:44:49

Considérons le programme suivant:

package main

import "fmt"

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

si je construis ceci sur ma machine Linux AMD64 (Go 1.9), comme ceci:

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

j'obtiens un binaire d'environ 2 Mo de taille.

la raison pour cela (qui a été expliqué dans d'autres réponses) est que nous utilisons le paquet "fmt" qui est assez grand, mais le binaire n'a pas non plus été dépouillé et cela signifie que la table de symboles est toujours là. Si nous demandons au compilateur de supprimer le binaire, il deviendra beaucoup plus petite:

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

cependant, si nous réécrivons le programme pour utiliser la fonction builtin print, au lieu de fmt.Println, comme ceci:

package main

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

Et puis le compiler:

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

on finit avec un binaire encore plus petit. C'est aussi petit que nous pouvons l'obtenir sans avoir recours à des trucs comme UPX-packing, donc le temps d'exécution est d'environ 700 Ko.

14
répondu Joppe 2017-09-11 22:08:50

notez que la question de taille binaire est suivie par numéro 6853 dans le projet golang / go.

Par exemple, valider a26c01a (pour Aller 1.4) couper bonjour tout le monde, par 70kB:

parce que nous n'écrivons pas ces noms dans la table de symboles.

considérant que le compilateur, l'assembleur, le linker et l'exécution pour 1.5 seront entièrement en route, vous pouvez vous attendre à une optimisation supplémentaire.

7
répondu VonC 2015-02-18 06:34:38