问题
当 Rust 调用创建子进程时,在 C/C++ 级别会发生几件事。这是一种简化,但有助于解释困境。
- 流被复制(使用 dup2 或类似调用)
- 父进程被分叉(使用 fork 或 clone 系统调用)
- 分叉的进程执行子进程(来自 execvp 系列的调用)
父子进程现在是并发进程。您当前使用的 Rust 调用似乎是一个克隆调用,其行为与纯分叉非常相似,因此您的大小为 20G x 2 - 32G = 8G,不考虑操作系统所需的空间以及其他任何可能的空间跑步。克隆调用以负返回值返回,并且 errno 由对 ENOMEM errno 的调用设置。
如果添加物理内存、压缩数据或通过不需要在任何时候将全部数据都存储在内存中的进程流式传输数据的架构解决方案不是选项,那么经典解决方案相当简单。
推荐
将父流程设计为精益。然后生成两个工人子节点,一个处理您的 20GB 需求,另一个处理您的 1 GB 需求1。这些孩子可以通过管道、文件、共享内存、套接字、信号量、信号和/或其他通信机制相互连接,就像父母和孩子一样。
从 Apache httpd 到嵌入式蜂窝塔路由守护程序的许多成熟软件包都使用这种设计模式。它可靠、可维护、可扩展且可移植。
32G 可能足以满足 20G 和 1G 处理需求,以及操作系统和精益父进程。
虽然此解决方案肯定会解决您的问题,但如果以后要重用或扩展代码,则可能有必要研究涉及数据帧或多维切片的潜在流程设计更改,以支持数据流和减少内存需求。
内存过度使用总是
将 overcommit_memory 设置为 1 会消除问题中引用的克隆错误条件,因为 Rust 调用调用读取该设置的 LINUX 克隆调用。但是这个解决方案有几个注意事项表明上述建议是优越的,主要是 1 的值是危险的,尤其是对于生产环境。
背景
关于 OpenBSD rfork 和克隆调用的内核讨论随后发生在 1990 年代末和 2000 年代初。源自这些讨论的特性允许比进程更少极端的分叉,这对称地就像在 pthread 之间提供更广泛的独立性一样。其中一些讨论已经对已进入 POSIX 标准化的传统流程衍生产生了扩展。
在 2000 年代初期,Linux Torvalds 提出了一种标志结构来确定执行模型的哪些组件是共享的,以及在执行分叉时复制哪些组件,从而模糊了进程和线程之间的区别。由此,克隆调用应运而生。
在这些线程中没有过多讨论过度使用的内存。设计目标是更多地控制分叉的结果,而不是将内存使用优化委托给操作系统启发式,这是overcommit_memory = 0 的默认设置所做的。
注意事项
内存过量使用超出了这些扩展,增加了权衡其模式的复杂性2、设计趋势警告3、实际运行时间限制4,以及性能影响5。
便携性和使用寿命
此外,如果没有标准化,使用内存过量使用的代码可能无法移植,并且寿命问题是相关的,尤其是当设置控制函数的行为时。如果设置系统发生更改,则无法保证向后兼容性,甚至会发出一些弃用警告。
危险
linuxdevcenter 文档2 说,“1 总是过度使用。也许你现在意识到这种模式的危险。”,还有其他迹象表明总是过度使用 6, 7.
在 LINUX、Windows 和 VMWare 上过度使用的实现者可以保证可靠性,但它是一个统计游戏,结合许多其他复杂的过程控制,可能会在某些条件下导致某些不稳定的特性。甚至 overcommit 这个名字也告诉我们一些关于它作为一种实践的真正特征。
一种非默认的 overcommit_memory 模式,其中有几个警告是问题,但适用于即时案例的即时试验可能会导致间歇性可靠性。
可预测性及其对系统可靠性和响应时间一致性的影响
从贝尔实验室开始,类 UNIX 操作系统中进程的概念是,进程向其容器(即操作系统)发出具体请求。结果既可预测又是二元的。请求被拒绝或被批准。一旦被授予,进程将获得对资源的完全控制权和直接访问权,直到进程放弃对资源的使用。
虚拟内存的交换空间方面违反了这一原则,当 RAM 被大量消耗时,它表现为工作站上的活动严重减速。例如,在开发过程中,有时需要等待十秒钟才能在显示屏上看到角色。
结论
有很多方法可以充分利用物理内存,但希望分配的内存使用很少,这样做可能会带来负面影响。过度使用过度使用时交换带来的性能损失是一个有据可查的例子。如果您在 RAM 中保留 20G 的数据,情况可能尤其如此。
仅分配需要的内容、以智能方式分叉、使用线程并释放肯定不再需要的内存会导致内存节俭而不影响可靠性、造成交换磁盘使用量的峰值,并且可以在没有警告的情况下操作达到限制系统资源。
Command::new调用的设计者的立场可能就是基于这个观点。在这种情况下,在 fork 后多久调用 exec 并不是在生成期间请求多少内存的决定因素。
注释和参考文献
[1] 生成工人子代可能需要进行一些代码重构,并且从表面上看似乎很麻烦,但重构可能非常简单且非常有益。
[2]http://www.linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html?page=2
[3]https://www.etalabs.net/overcommit.html
[4]http://www.gabesvirtualworld.com/memory-overcommit-in-production-yes-yes-yes/
[5]https://labs.vmware.com/vmtj/memory-overcommitment-in-the-esx-server
[6]https://github.com/kubernetes/kubernetes/issues/14452
[7]http://linuxtoolkit.blogspot.com/2011_08_01_archive.html