为什么CGO_ENABLE实现在虚拟内存中的这种影响?

问题描述 投票:2回答:1

我有一个小守护写在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是一个公正的虚拟内存,说实在的,不使用的过程”。

go
1个回答
4
投票

我可以做一个猜测。

正如你可能知道,“参考”去实现(被称为历史上“GC”;那一个,可从the main site下载)的编译器默认生成静态链接的二进制文件。这意味着,这种代码只依靠由操作系统内核提供的所谓的“系统调用”,不依赖于操作系统(或第三方)提供的任何共享库。

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

这种“扭曲”出来的两种需要转到标准库必须与操作系统交互:

  1. DNS解析,这是由net包所需。
  2. 用户和组的查找,这是由os包所需。

这里的问题是双重的:

  • 在Linux本身(也就是内核,而不是整个OS)不提供任何手段来执行这些任务。
  • 任何典型的类UNIX系统中,因为永远,为双方提供使用那些所谓的“NSS”特殊设施,这是“名称服务转换”¹任务。 在NSS为可插拔模块可作为特定类型的数据库查询提供:DNS,用户/组数据库,和多个(诸如众所周知的名字的“服务”等)。非标准提供商的用户/组数据库的一个假想相当常见的例子是一个本地服务,其接触的LDAP服务器。

在一个典型的基于Linux的GNU / OS的NSS由libc实现(在不太典型的系统可能由一个单独的共享库中提供但这并不太大变化)。

自 - 再次,通常, - 该libc是在API方面具有相当稳定的库(它甚至还提供了版本的符号是面向未来的),转到作者理所当然地决定,链接到的libc导入符号的最小的子集(主要是getaddrinfogetnameinfogetpwnam_r等)即可在默认情况下进行,因为它是安全的情况下99%,而当它不是,那些谁拥有处理这些案件通常都知道该怎么做呢。

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

如果cgo被禁用,则转到编译器,而不是在自己的后备实现它试图模仿一个什么样的全面的NSS实现执行的一个子集的链接(即解析/etc/resolv.conf和使用来自它的信息直接查询这里列出的DNS服务器,解析/etc/passwd/etc/group服务于用户/组的数据库查询)。

正如你所看到的,在默认情况下,

  • libc被映射,以及
  • 它被初始化,并使用一些内存为自己的需求 - 如NSS调用返回的数据明显的缓存。

相反,当cgo被禁用的情况下,上述两件事情不会发生。您有更多的STDLIB的代码链接的静态中,但貌似默认情况下只胜过整体累计RSS使用方面的后者。

考虑研究this query的输出额外的乐趣;-)


¹不混淆与Mozilla的libnss

© www.soinside.com 2019 - 2024. All rights reserved.