【问题标题】:Why does CGO_ENABLE make a such impact on virtual memory?为什么 CGO_ENABLE 会对虚拟内存产生如此大的影响?
【发布时间】:2019-06-24 15:35:18
【问题描述】:

我有一个用 Golang 编写的小守护进程,它循环工作并执行一些操作。我发现,在使用 CGO_ENABLE=1 或 CGO_ENABLED=0 编译的情况下,守护程序的行为会有所不同。例如,在 CGO_ENABLE=1(默认值)的情况下,程序的 VSZ 在短时间内(一小时内)膨胀到 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 的包或函数。其他 Go 编写的程序表现出相同的行为。我知道 VSZ 和 RSS 之间的区别,我很感兴趣这种行为的本质是什么?为什么用 CGO_ENABLED=1 编译的程序要求从内核提供这么多内存?

我更喜欢不是“别担心,VSZ 只是虚拟内存,实际上它不被进程使用”形式的答案。

【问题讨论】:

  • 您可以比较 /proc/$pid/maps 来找出答案。 VSZ 不是“内核提供的内存”。毕竟它是虚拟的,包括换出的内存、与其他程序共享的内存、内存映射文件和其他东西。同样,/proc/$pid/maps 有故障。
  • @Peter,谢谢,但我在上面提到过我知道 VSZ 是什么。也许我使用了一些不正确的描述。 maps-file 对我来说也是众所周知的。我问了,为什么 CGO_ENABLED 会影响程序描述的行为,而不是 VSZ。
  • 你是在 Linux 上试试这个吗?
  • 是的,它在 Linux 上

标签: go


【解决方案1】:

我可以做出有根据的猜测。

您可能知道,“参考”Go 实现(历史上称为“gc”;可从the main site 下载)的编译器默认生成静态链接的二进制文件。这意味着,此类二进制文件仅依赖于操作系统内核提供的所谓“系统调用”,而不依赖于操作系统(或第三方)提供的任何共享库。

在基于 Linux 的平台上,这并不完全正确:在默认设置中(在 Linux 上为 Linux 构建,即不交叉编译)生成的二进制文件实际上与 libc 链接 和libpthread(间接,通过libc)。

这种“扭曲”源于 Go 标准库必须与操作系统交互的两个需求:

  1. DNS 解析,net 包需要。
  2. os 包需要用户和组查找。

这里的问题有两个:

  • Linux本身(即内核,而不是整个操作系统)不提供任何方法来执行这些任务。

  • 任何典型的类 UNIX 系统,自古以来,都使用称为“NSS”的特殊工具来提供这两个任务, 这是“名称服务开关”¹。

    NSS 提供了可插入的模块,这些模块可以为 作为提供特定类型查询的数据库:DNS、用户/组数据库等(例如“服务”的知名名称等)。一个据说相当普遍的例子 用户/组数据库的非标准提供者是本地的 联系 LDAP 服务器的服务。

在典型的基于 GNU/Linux 的操作系统上,NSS 由 libc(在不太典型的系统上,它可能由 单独的共享库,但这并没有太大变化)。

因为——再次,通常,——libc 是一个相当稳定的 就其 API 而言的库(它甚至提供版本化符号 为了面向未来),Go 作者正确地决定链接 libc 以导入符号的最小子集(主要是 getaddrinfogetnameinfogetpwnam_r 等)是可以的 默认情况下完成,因为它对 99% 的情况是安全的, 如果不是,那些必须处理这些案件的人通常 无论如何都知道该怎么做。

因此,默认情况下cgo 已启用并使用使用 NSS 实现这些查找。

如果 cgo 被禁用,Go 编译器会改为链接自己的 回退实现,它试图模仿一个子集 成熟的 NSS 实现(即解析 /etc/resolv.conf 并使用其中的信息直接查询此处列出的 DNS 服务器;解析 /etc/passwd/etc/group 以服务于用户/组数据库查询)。

如您所见,在默认情况下,

  • libc 被映射,并且
  • 它已初始化并使用一些内存来满足自己的需要 — 例如明显缓存 NSS 调用返回的数据。

反之,在cgo被禁用的情况下,上述两件事都不会发生。您有更多静态链接的 stdlib 代码,但看起来默认情况仅在整体累积 RSS 使用量方面胜过后一种情况。

考虑研究 this query 为了更多的乐趣;-)


¹不要与 Mozilla 的 libnss 混淆。

【讨论】:

  • 谢谢,这听起来很合理。还有关于cgo 的更多细节
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-02
  • 2010-11-28
  • 2011-09-10
  • 2013-11-18
  • 2011-03-15
  • 1970-01-01
相关资源
最近更新 更多