I could make an educated guess.
As you probably know, the compiler of the "reference" Go implementation (historically dubbed "gc"; that one, available for download from the main site) by default produces statically-linked binaries. This means, such binaries rely only on the so-called "system calls" provided by the OS kernel and do not depend on any shared libraries provided by the OS (or 3rd parties).
On Linux-based platforms, this is not completely true: in the default setting (building on Linux for Linux, i.e., not cross-compiling) the generated binary is actually linked with
libpthread (indirectly, via
This "twist" comes out of the two needs the Go standard library has to interact with the OS:
- DNS resolving, which is needed by the
- User and group lookup, which is needed by the
The problem here is two-fold:
The Linux itself (that is, the kernel, not the whole OS) does not provide any means to carry out those tasks.
Any typical UNIX-like system, since forever, provides for both those tasks using a special facility called "NSS", which is the "Name-Service Switch"¹.
The NSS provides for pluggable modules which can serve as the databases offering queries of particular type: DNS, user/group database, and more (such as well-known names for "services" etc). A supposedly rather common example of a non-standard provider for the user/group databases is a local service which contacts an LDAP server.
On a typical GNU/Linux-based OS the NSS is implemented by
libc (on less typical systems it might be provided by a
separate shared library but this does not change much).
Since — again, typically, — the
libc is a rather stable
library in terms of its API (it even provides versioned symbols
to be future-proof), the Go authors rightfully decided that linking against
libc to import a minimal subset of symbols (mostly
getpwnam_r etc) is OK
to be done by default as it's safe for 99% of cases,
and when it isn't, those who have to tackle these cases usually
know what to do anyway.
So, by default
cgo is enabled and used to implement these lookups using NSS.
cgo is disabled, the Go compiler instead links in its own
fallback implementations which try to mimic a subset of what a
full-blown NSS implementation does (i.e. parse
/etc/resolv.conf and use the information from it to directly query the DNS servers listed here; parse
/etc/group to serve the user/group database queries).
As you can see, in the defult case,
libcgets mapped in, and
- It is initialized and uses some memory for its own needs — such as obvious caching of the data the NSS calls return.
Conversely, in the case when
cgo is disabled, the above two things do not happen. You have more stdlib code linked in statically but looks like the default case merely trumps the latter one in terms of the overall cumulative RSS usage.
Consider studying the output of this query for additional fun ;-)
¹ not to be confused with Mozilla's