2015-02-18 13 views
33

Ho eseguito un programma Hello World che ha generato un eseguibile nativo sulla mia macchina Linux. Ma sono stato sorpreso di vedere la dimensione del semplice programma Hello world Go, era 1.9 MB!Motivo dell'enorme dimensione dell'eseguibile compilato di Go

Perché è così grande l'eseguibile di un programma così semplice in Go?

+7

Enorme? Immagino che tu non faccia molto Java allora! –

+4

Beh, im da sfondo C/C++! –

+0

Ho appena provato questo mondo ciao-scala nativo: http://www.scala-native.org/en/latest/user/sbt.html#minimal-sbt-project Ci è voluto un po 'di tempo per compilare, scaricare un sacco di roba, e il binario è 3.9MB. – bli

risposta

37

Questa domanda esatta compare nelle FAQ ufficiale: Why is my trivial program such a large binary?

Citando la risposta:

I linker nella catena strumento gc (5l, 6l, e 8l) fare il collegamento statico. I file binari All Go includono quindi il tempo di esecuzione Go, insieme alle informazioni sul tipo di esecuzione necessarie per supportare i controlli di tipo dinamico, la riflessione e persino le tracce dello stack di panico.

Un semplice programma C "ciao, mondo" compilato e collegato staticamente tramite gcc su Linux è di circa 750 kB, compresa un'implementazione di printf. Un programma Go equivalente che utilizza fmt.Printf è di circa 1,9 MB, ma include un supporto più potente in fase di esecuzione e informazioni sul tipo.

Così l'eseguibile nativo del Ciao Mondo è di 1,9 MB perché contiene un runtime che consente la raccolta dei rifiuti, di riflessione e di molte altre caratteristiche (che il programma non potrebbe davvero usare, ma è lì). E l'implementazione del pacchetto fmt che hai usato per stampare il testo "Hello World" (più le sue dipendenze).

Ora provare quanto segue: aggiungere un'altra riga fmt.Println("Hello World! Again") al programma e compilarla di nuovo. Il risultato non sarà 2x 1.9 MB, ma solo 1.9 MB! Sì, perché tutte le librerie utilizzate (fmt e le sue dipendenze) e il runtime sono già stati aggiunti all'eseguibile (e quindi verranno aggiunti solo pochi byte per stampare il secondo testo che hai appena aggiunto).

7

Si noti che il problema relativo alle dimensioni binarie è tracciato da issue 6853 nello golang/go project.

Per esempio, commit a26c01a (per Go 1.4) taglio ciao mondo da 70KB:

perché non scriviamo quei nomi nella tabella dei simboli.

considerando il compilatore, assemblatore, linker, e runtime per 1,5 saranno interamente in Go, ci si può aspettare un'ulteriore ottimizzazione.

+0

Non vedo che cosa abbia a che fare con il linguaggio di implementazione. Hanno bisogno di usare le librerie condivise. Un po 'incredibile che non lo fanno già in questo giorno ed età. – EJP

+0

@EJP: Perché hanno bisogno di usare le librerie condivise? – Flimzy

+4

@EJP, parte della semplicità di Go sta nel non utilizzare le librerie condivise. In effetti, Go non ha alcuna dipendenza, utilizza semplici syscalls. Basta distribuire un singolo binario e funziona. Ciò danneggerebbe in modo significativo la lingua e il suo ecosistema se fosse altrimenti. – creker

4

Si consideri il seguente programma:

package main 

import "fmt" 

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

Se costruisco questo sulla mia macchina Linux AMD64 (Go 1.9), in questo modo:

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

ottengo aa binario che è di circa 2 Mb in dimensione.

La ragione di questo (che è stato spiegato in altre risposte) è che stiamo utilizzando il pacchetto "fmt" che è abbastanza grande, ma il binario non è anche stata spogliata e questo significa che la tabella dei simboli è ancora lì .Se invece il compilatore per mettere a nudo il binario, diventerà molto più piccolo:

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

Tuttavia, se riscriviamo il programma di utilizzare la funzione built-in di stampa, invece di fmt.Println, in questo modo:

package main 

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

e quindi compilare esso:

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

si finisce con un binario ancora più piccolo. Questo è il minimo che possiamo ottenere senza ricorrere a trucchi come UPX-packing, quindi il sovraccarico di Go-runtime è di circa 700 Kb.

Problemi correlati