C 代码是否享受 Go GC 的碎片预防策略?

Does C Code enjoy the Go GC's fragmentation prevention strategies?

更正了错误的含义:

Golang 的 GC 执行虚拟地址 space 碎片整理 碎片预防策略,这使程序能够 运行 很长一段时间(如果从来没有) ).

但似乎 C 代码(cgo 或 SWIG)无法更新它的内存指针以防它们被移动到别处。 从这些策略中获益。

  1. 这是真的吗? C代码不会受益于Golang的虚拟地址space defragmentation fragmentation-prevention,最终得到碎片吗?

  2. 如果那是假的,怎么办?

  3. 此外,C 代码加载的任何 DLL 代码(例如 Windows DLL)会怎样?

(更新问题纠正错误假设)

视情况而定。

C代码需要的内存可以通过Go分配,并将其指针传递给C代码。在这种情况下,C 代码将受益于 Go 的 fragmentation-prevention 策略。

DLL 代码也是如此,因此如果 DLL 函数不自行分配工作内存,也可以为它们完成此操作。

恐怕您在这里的多个层面上都感到困惑。

首先,在 production-grade Go 代码中调用 C 是 通常 从一开始就 no-go: 它很慢;和进行系统调用一样慢——至于大多数情况下它确实作为系统调用工作:需要从 Go 堆栈切换到 C 堆栈并让 OS 线程恰好正在执行使 cgo 调用被锁定到该线程的 Go 代码,即使 C 端的某些东西阻塞了。

这并不是说你必须避免调用 C,但这意味着你需要预先考虑这个问题 并衡量。 可能正在建立一个工人池将需要进行 C 调用的任务散布到其上的 goroutines。

其次,您对内存的担忧可能是没有根据的;让我解释一下。

碎片化 虚拟 内存应该是现代系统上的 non-issue 通常用于 运行 Go 程序(我的意思是 amd64 之类的)。 这几乎是因为分配虚拟内存不会强制 OS 实际分配 physical 内存页——后者只发生 当虚拟内存被 used 时(即在某个地址访问 碰巧指向分配的虚拟内存区域)。 所以,不管你愿意与否,你确实有那个物理内存碎片问题 无论如何,它正在得到解决 在 OS 和 CPU 级别使用 multiple-layered 地址转换 表(和 TLB-caches)。

第三,您似乎陷入了一个常见的陷阱,即猜测 事情将如何在负载下执行而不是编写一个高度简化的 模型程序并检查它在估计产量下的表现 加载。也就是说,你认为分配C内存会出现问题 然后幻想整个事情都行不通。

我会说你的担心是没有根据的——考虑到生产量 用 C 和 C++ 编写并在硬核负载下工作的代码。

最后,C 和 C++ 程序员踏上了通往 high-performance 的道路 很久以前的内存管理。一个典型的解决方案是使用自定义 显示最多的对象的池分配器 allocation/deallocation 在典型负载下流失。通过这种方法, 在 C 端分配的内存在整个生命周期内基本稳定 你的程序。

TL;DR

写一个模型程序,把估计的负载放在上面,看看它的行为。 然后分析内存有什么问题,如果有的话,还有 然后才开始攻击他们。