DEV Community

Cover image for Getting Going with Go, Day 3
Kai
Kai

Posted on

Getting Going with Go, Day 3

Compiled files in Go

A slight digression today. I noticed that the compiled size of my “hello, world!” program from yesterday was a whopping 2 megabytes, so I’m going to explore reasons for that along with what happens at compilation time.

kai:~/helloworld/$ ll
total 4200
-rwxr-xr-x  1 kai  staff   2.0M 26 Jan 15:12 helloworld*
-rw-r--r--  1 kai  staff    74B 26 Jan 16:43 main.go
Enter fullscreen mode Exit fullscreen mode

So, of course, the first thing I did was to create an “empty” program that does absolutely nothing. Its source code is as follows:

package main

func main() {

}
Enter fullscreen mode Exit fullscreen mode

After running go build on that, turns out the Mac executable is still 1.1MB. So, the base minimum size for any Go program is over a megabyte. Still, they compile and run extremely quickly, so maybe that’s not a bad thing? We have plenty of bandwidth and memory these days…

But what are the reasons for such relatively large binary files for things that are so simple, or in the case of the above example, do nothing at all? Turns out, unsurprisingly, it has to do with what’s bundled into the executable. The official Go FAQ goes into this in a bit more detail, and compares the build size of a Hello World program in C (750KB or so) and in Go (2MB). The key here is in the concept of static linking. All the packages and required assets are bundled into one thing that gets compiled for a specific computer architecture. That means that my compiled Go program can be sent to anyone with a Mac and it will just run. No requirements to check “oh, do you have X installed?” or “make sure you are running version X of Y”. It just runs. The file size is the price you pay for that.

The bundled information alongside the raw "this is what your program will do" includes some clever debugging and stack trace information, according to the Go FAQ. This is borne out by the analysis done by Raphael 'kena' Poss at Cockroach Labs which shows that the runtime information, as in "this is what your computer needs to know about running this code" is 900K of any given Go program.

If I'm only using one (the Println) method of the fmt package, is it worth importing the whole thing? The answer, at least to me today, right now, is "yeah". There is zero incentive for me to start learning inventing the wheel to implement some sort of "print to screen" functionality in order to shave off some Kilobytes. I'm not programming for the Demoscene anyway.

This interesting sidetrack has got me reading about all the Go standard library. There's implementations for everything from zipping and unzipping files, as well as encoding and decoding jpeg files. Personally, I've always found it a bit of a mental challenge to find out "has X already been implemented, and how to find out about it?" as well as remembering all of it. I think a good rule of thumb might be to rubber duck as I go and google "how to do in " pretty much before I do anything new to avoid an embarrassment of "uh, why have you implemented a horrendously inefficient way to do this when there's a perfectly good internal method provided by the standard library?"

References and further reading

Short one for today, as I have had a headache all day. Hopefully more in-depth tomorrow.

Top comments (0)