我有一个小守护写在Golang,它工作在一个循环,并做一些事情。我发现,当它与CGO_ENABLE = 1或CGO_ENABLED = 0编译的情况下守护进程的行为不同。例如,对于CGO_ENABLE = 1(这是默认值)该程序的过程中VSZ短时间内(1小时内)涨大到1-2GB。与CGO_ENABLED = 0,VSZ是在所述时间长周期(数天)相同。看看下面的数字:
CGO_ENABLED = 1(守护程序工作5分钟)
$ grep -E 'VmSize|VmRSS' /proc/14916/status
VmSize: 1084052 kB
VmRSS: 12524 kB
CGO_ENABLED = 0(守护程序工作〜30小时)
$ grep -E 'VmSize|VmRSS' /proc/15160/status
VmSize: 110232 kB
VmRSS: 9756 kB
守护程序不使用CGO-依赖的软件包或功能。其他围棋编写的程序表现出相同的行为。我知道VSZ和RSS的区别,我有趣的是这种行为的本质是什么?为什么要与CGO_ENABLED = 1编译的程序要求从内核提供这么多的内存?
我宁愿不在形式回答“不用担心,VSZ是一个公正的虚拟内存,说实在的,不使用的过程”。
我可以做一个猜测。
正如你可能知道,“参考”去实现(被称为历史上“GC”;那一个,可从the main site下载)的编译器默认生成静态链接的二进制文件。这意味着,这种代码只依靠由操作系统内核提供的所谓的“系统调用”,不依赖于操作系统(或第三方)提供的任何共享库。
在基于Linux平台,这并不完全正确:在默认设置(在Linux上为Linux的建设,即不交叉编译)所生成的二进制与libc
与libpthread
(间接通过libc
,)实际上的联系。
这种“扭曲”出来的两种需要转到标准库必须与操作系统交互:
net
包所需。os
包所需。这里的问题是双重的:
在一个典型的基于Linux的GNU / OS的NSS由libc
实现(在不太典型的系统可能由一个单独的共享库中提供但这并不太大变化)。
自 - 再次,通常, - 该libc
是在API方面具有相当稳定的库(它甚至还提供了版本的符号是面向未来的),转到作者理所当然地决定,链接到的libc
导入符号的最小的子集(主要是getaddrinfo
,getnameinfo
,getpwnam_r
等)即可在默认情况下进行,因为它是安全的情况下99%,而当它不是,那些谁拥有处理这些案件通常都知道该怎么做呢。
因此,在默认情况下cgo
已启用,用于实现使用NSS这些查找。
如果cgo
被禁用,则转到编译器,而不是在自己的后备实现它试图模仿一个什么样的全面的NSS实现执行的一个子集的链接(即解析/etc/resolv.conf
和使用来自它的信息直接查询这里列出的DNS服务器,解析/etc/passwd
和/etc/group
服务于用户/组的数据库查询)。
正如你所看到的,在默认情况下,
libc
被映射,以及相反,当cgo
被禁用的情况下,上述两件事情不会发生。您有更多的STDLIB的代码链接的静态中,但貌似默认情况下只胜过整体累计RSS使用方面的后者。
考虑研究this query的输出额外的乐趣;-)
¹不混淆与Mozilla的libnss
。