Exploring size of Binaries created by Go
Go is the modern programming language from Google. It compiles to a standalone binary. Reminds us of the old C programming days. So I set out to see how tight is the binary. First step in the experiment is to see how the C programs work today (havent written one in a while).
#include <stdio.h>
void main() {
printf("hello world");
}
Now let us look at the equivalent Go program.
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
Yep looks fairly similar and simple. Namespaces didn’t exist in C hence the extra bits. Now comes the crucial part, let us look at the binaries.
pi@piguard:~/gotest $ gcc --version
gcc (Raspbian 8.3.0-6+rpi1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
pi@piguard:~/gotest $ go version
go version go1.14.4 linux/arm
Using the old world workhorse gcc and the current stable Go 1.14.4 version. What is unique is that I am doing all this on a Raspberry Pi running Debian Buster (10). Why you may ask? I wanted a modern compiled code generator for the Pi and my choice was C/C++ and Go. Decided to pick Go because of its rising popularity.
Now let us compile them all and look at the size of the binary files.
pi@piguard:~/gotest $ gcc helloworld.c -o helloworld.c.bin
pi@piguard:~/gotest $ go build helloworld.go -o helloworld.go.bin
pi@piguard:~/gotest $ ls -lah
total 1.8M
drwxr-xr-x 2 pi pi 4.0K Jun 14 23:05 .
drwxr-xr-x 9 pi pi 4.0K Jun 14 22:56 ..
-rwxr-xr-x 1 pi pi 1.9M Jun 14 23:05 helloworld.go.bin
-rw-r--r-- 1 pi pi 61 Jun 14 22:59 helloworld.c
-rwxr-xr-x 1 pi pi 7.9K Jun 14 23:04 helloworld.c.bin
-rw-r--r-- 1 pi pi 73 Jun 14 18:46 helloworld.go
The c binary was 7.9K while Go was 1.9MB. Why? Apparently Go bundles the entire standard library binaries along with every executable that it generates. You might ask doesnt a C compiler do the same? We did call printf() in the code. The answer is yes, the C compiles does bundle it too but it is granular at a function level while Go’s standard libraries are not that granular. Now that is fairly vague but if you want to explore the depths of this, A detailed report by the Cockroach DB team will give you tools and a method to analyze the size of binaries in Go.
The language designer’s decision to reduce startup time of a Go binary by compromising on space seems to the essence of the explanation for large sized binaries.
There is one tried and tested technique on Unix systems to reduce the binary file size using the unix strip command. It strips all the debug informtion and reduces the size of the binaries. I ran strip on both the Go and C binary. Here is the output.
pi@piguard:~/gotest $ ls -alh
total 1.3M
drwxr-xr-x 2 pi pi 4.0K Jun 14 23:28 .
drwxr-xr-x 9 pi pi 4.0K Jun 14 22:56 ..
-rwxr-xr-x 1 pi pi 1.3M Jun 14 23:28 helloworld.go.bin
-rw-r--r-- 1 pi pi 61 Jun 14 22:59 helloworld.c
-rwxr-xr-x 1 pi pi 5.5K Jun 14 23:28 helloworld.c.bin
-rw-r--r-- 1 pi pi 73 Jun 14 18:46 helloworld.go
A good 32% drop in size. I think this is all we can hope for now until Go makes some changes to its packaging mechanism.