我可以做出有根据的猜测。
您可能知道,“参考”Go 实现的编译器(历史上称为“gc”;可以从主站点 https://golang.org) 默认情况下生成静态链接的二进制文件。这意味着,此类二进制文件仅依赖于操作系统内核提供的所谓“系统调用”,而不依赖于操作系统(或第三方)提供的任何共享库。
在基于 Linux 的平台上,这并不完全正确:在默认设置(在 Linux for Linux 上构建,即不交叉编译)中,生成的二进制文件实际上与libc
与libpthread
(间接地,通过libc
).
这种“扭曲”源于 Go 标准库与操作系统交互的两个需求:
- DNS解析,这是需要的
net
包裹。
- 用户和组查找,这是需要的
os
包裹。
这里的问题有两个:
Linuxitself(即内核,而不是整个操作系统)不提供任何方法来执行这些任务。
-
任何典型的类 UNIX 系统永远都使用称为“NSS”的特殊工具来提供这两项任务,
这是“名称服务开关”。
NSS 提供可插拔模块,可用于
作为提供特定类型查询的数据库:DNS、用户/组数据库等(例如众所周知的“服务”名称等)。一个据说相当常见的例子
用户/组数据库的非标准提供者是本地
联系 LDAP 服务器的服务。
在典型的基于 GNU/Linux 的操作系统上,NSS 是通过以下方式实现的libc
(在不太典型的系统上,它可能由
单独的共享库但这并没有太大变化)。
因为——同样,通常——libc
是一个比较稳定的
库就其 API 而言(它甚至提供版本化符号
为了面向未来),Go 作者正确地决定链接libc
导入符号的最小子集(主要是getaddrinfo
, getnameinfo
, getpwnam_r
等)就可以了
默认情况下这样做,因为在 99% 的情况下这是安全的,
如果不是,那些必须处理这些案件的人通常
无论如何知道该怎么做。
所以,默认情况下cgo
已启用and used使用 NSS 来实现这些查找。
If cgo
被禁用,Go 编译器会链接到它自己的
后备实现试图模仿一个子集
成熟的 NSS 实现确实如此(即解析/etc/resolv.conf
并使用其中的信息直接查询此处列出的 DNS 服务器;解析/etc/passwd
and /etc/group
为用户/组数据库查询提供服务)。
正如你所看到的,在默认情况下,
- The
libc
被映射到,并且
- It is 已初始化并使用一些内存来满足自己的需要 -
例如明显缓存 NSS 调用返回的数据。
相反,在这种情况下,当cgo
禁用后,上述两件事就不会发生。您有更多静态链接的 stdlib 代码,但看起来默认情况在总体累积 RSS 使用方面仅胜过后一种情况。
考虑研究输出这个查询 https://www.google.com/search?q=CGO_ENABLED+site%3Ahttps%3A%2F%2Fgolang.org%2Fdoc为了额外的乐趣;-)
切勿与 Mozilla 的混淆libnss https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS.