C 代码是否享受 Go GC 的碎片预防策略?
Does C Code enjoy the Go GC's fragmentation prevention strategies?
更正了错误的含义:
Golang 的 GC 执行虚拟地址 space 碎片整理 碎片预防策略,这使程序能够 运行 很长一段时间(如果从来没有) ).
但似乎 C 代码(cgo 或 SWIG)无法更新它的内存指针以防它们被移动到别处。 从这些策略中获益。
这是真的吗? C代码不会受益于Golang的虚拟地址space defragmentation fragmentation-prevention,最终得到碎片吗?
如果那是假的,怎么办?
此外,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
写一个模型程序,把估计的负载放在上面,看看它的行为。
然后分析内存有什么问题,如果有的话,还有
然后才开始攻击他们。
更正了错误的含义:
Golang 的 GC 执行虚拟地址 space 碎片整理 碎片预防策略,这使程序能够 运行 很长一段时间(如果从来没有) ).
但似乎 C 代码(cgo 或 SWIG)无法更新它的内存指针以防它们被移动到别处。 从这些策略中获益。
这是真的吗? C代码不会受益于Golang的虚拟地址space
defragmentationfragmentation-prevention,最终得到碎片吗?如果那是假的,怎么办?
此外,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
写一个模型程序,把估计的负载放在上面,看看它的行为。 然后分析内存有什么问题,如果有的话,还有 然后才开始攻击他们。