- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有一个用 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 只是一个虚拟内存,实际上它不被进程使用”形式的答案。
最佳答案
我可以做出有根据的猜测。
您可能知道,“引用”Go 实现的编译器(历史上称为“gc”;那个,可从 the main site 下载)默认生成静态链接的二进制文件。这意味着,此类二进制文件仅依赖于操作系统内核提供的所谓“系统调用”,而不依赖于操作系统(或第 3 方)提供的任何共享库。
在基于 Linux 的平台上,这并不完全正确:在默认设置(为 Linux 构建 Linux,即不交叉编译)中,生成的二进制文件实际上与 libc
链接并使用 libpthread
(间接地,通过 libc
)。
这种“扭曲”源于 Go 标准库必须与操作系统交互的两个需求:
net
包需要它。os
包所需的用户和组查找。这里的问题有两个:
Linux 本身(即内核,而不是整个操作系统)不提供任何方法来执行这些任务。
自古以来,任何典型的类 UNIX 系统都使用称为“NSS”的特殊工具来完成这两项任务,这是“名称服务开关”¹。
NSS 提供可插拔模块,可以服务于作为提供特定类型查询的数据库:DNS、用户/组数据库等(例如“服务”的知名名称等)。一个据称相当常见的例子用户/组数据库的非标准提供者是本地的联系 LDAP 服务器的服务。
在典型的基于 GNU/Linux 的操作系统上,NSS 是通过以下方式实现的libc
(在不太典型的系统上,它可能由单独的共享库,但这并没有太大变化。
因为——同样,通常——libc
是一个相当稳定的库在其 API 方面(它甚至提供版本化符号为了面向 future ),Go 作者正确地决定链接 libc
以导入最小的符号子集(主要是 getaddrinfo
、getnameinfo
、 getpwnam_r
等)就可以了默认情况下完成,因为它在 99% 的情况下都是安全的,如果不是,那些必须处理这些案件的人通常无论如何都知道该怎么做。
因此,默认情况下 cgo
已启用并用于使用 NSS 实现这些查找。
如果 cgo
被禁用,Go 编译器会链接到它自己的试图模仿一个子集的后备实现完整的 NSS 实现(即解析 /etc/resolv.conf
并使用其中的信息直接查询此处列出的 DNS 服务器;解析 /etc/passwd
和/etc/group
为用户/组数据库查询提供服务。
如您所见,在默认情况下,
libc
被映射,并且相反,在禁用cgo
的情况下,上述两件事不会发生。您有更多静态链接的 stdlib 代码,但看起来默认情况在整体累积 RSS 使用方面仅胜过后者。
考虑研究输出 this query为了额外的乐趣 ;-)
¹ 不要与 Mozilla 的 libnss
混淆.
关于go - 为什么 CGO_ENABLE 会对虚拟内存产生如此大的影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54456100/
我们正在编译我们的 Go 代码以在 docker 上运行,并且我们正在调查为什么我们的二进制文件没有执行。我们发现它缺少一些动态库(尽管我们需要静态链接的二进制文件)。 这就是它的编译方式。env G
问题 请帮助理解 CGO_ENABLED 何时是必须且不可避免的,以及 go 编译过程会发生什么。 当 CGO_ENABLED 是必须的 在阅读了 引用 中的文章后,它似乎对目标平台有交叉编译原生支持
我有一个用 Golang 编写的小守护进程,它循环工作并做一些事情。我发现,在使用 CGO_ENABLE=1 或 CGO_ENABLED=0 编译时,守护进程的行为有所不同。例如,在 CGO_ENAB
CGO_ENABLED=1 我相信是当前的默认值,这意味着它取决于 GLIBC,它可以在更新和发行版之间进行重大更改。 CGO_ENABLED=0 是创建静态独立二进制文件的解决方法,为什么这不是默认
在编写利用网络的程序时,您会发现 CGO_ENABLED=0 的编译速度明显变慢。 例如最简单的HTTP服务器: package main import ( "flag" "fmt"
由于 libusb 依赖性,我正在尝试使用 CGO_ENABLED=1 为 Raspberry Pi 交叉编译 Golang 应用程序 在编译过程中出现错误: arm-linux-gnueabihf/
在 go/src 中的 make.bat 文件中(在解压缩 tar 之后),甚至在使用 CGO_ENABLED 检查之前就有一个 gcc 编译命令。这会扰乱引导工具构建。 出于安全原因,我无法通过 c
我想在 Golang 项目中使用 sqlite3。但是在 docker 容器中运行它有一些错误。二进制文件是用 'CGO_ENABLED=0' 编译的,go-sqlite3 需要 cgo 才能工作。这
cd /usr/local/go/src CGO_ENABLED=0 GOOS=linux GOARCH=arm ./make.bash # Building C bootstrap tool. cm
我是一名优秀的程序员,十分优秀!