加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

unix – 为什么使用`clone`创建进程会导致内存不足?

发布时间:2020-12-15 22:39:34 所属栏目:安全 来源:网络整理
导读:我有一个在32GB机器上分配大约20GB RAM的进程.在一些事件之后,我将数据从父进程流式传输到子进程的stdin.在子进程生成时,必须在父进程中保留20GB的数据. 该应用程序是用Rust编写的,我正在调用Command :: new(‘path / to / command’)来创建子进程. 当我生成
我有一个在32GB机器上分配大约20GB RAM的进程.在一些事件之后,我将数据从父进程流式传输到子进程的stdin.在子进程生成时,必须在父进程中保留20GB的数据.

该应用程序是用Rust编写的,我正在调用Command :: new(‘path / to / command’)来创建子进程.

当我生成子进程时,操作系统正在捕获内存不足错误.

strace输出:

[pid 747] 16:04:41.128377 clone(child_stack=0,flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,child_tidptr=0x7ff4c7f87b10) = -1 ENOMEM (Cannot allocate memory)

陷阱为什么会发生?子进程的消耗不应超过1GB,并且在clone()之后立即调用exec().

解决方法

问题

当Rust调用创建子进程时,在C/C++级别会发生一些事情.这是一种简化,但它有助于解释这种困境.

>流重复(使用dup2或类似的调用)
>父进程是分叉的(使用fork或clone系统调用)
>分叉进程执行子进程(来自execvp系列的调用)

父和子现在是并发进程.您当前正在使用的Rust调用似乎是一个克隆调用,其行为与纯分叉非常相似,因此您不需要考虑操作系统所需的空间和其他可能的空间,因此您需要20G x 2 – 32G = 8G.运行.克隆调用返回负返回值,并且通过调用ENOMEM errno设置errno.

如果在任何时候添加物理内存,压缩数据或通过不需要整个内存的过程流式传输的架构解决方案都不是选项,那么经典的解决方案相当简单.

建议

将父流程设计为精益流程.然后产生两个工作者子项,一个处理20GB需求,另一个处理1 GB需求1.这些孩子可以通过管道,文件,共享存储器,套接字,信号量,信令和/或其他通信机制彼此连接,就像父母和孩子一样.

从Apache httpd到嵌入式单元塔路由守护进程的许多成熟软件包都使用这种设计模式.它可靠,可维护,可扩展且便携.

32G可能足以满足20G和1G处理需求,以及操作系统和精益父进程.

尽管此解决方案肯定会解决您的问题,但如果要在以后重用或扩展代码,则可能有必要研究涉及数据帧或多维切片的潜在流程设计更改,以支持数据流和内存需求减少.

记忆总是过度使用

将overcommit_memory设置为1可消除问题中引用的克隆错误条件,因为Rust调用会调用读取该设置的LINUX克隆调用.但是这个解决方案有几点需要注意,上述建议可以说是优越的,主要是1的值是危险的,特别是对于生产环境.

背景

关于OpenBSD rfork和克隆调用的内核讨论随后发生在20世纪90年代末和21世纪初.这些讨论产生的特征允许比流程更少的极端分叉,这与pthreads之间提供更广泛的独立性是对称的.其中一些讨论产生了对已进入POSIX标准化的传统流程产生的扩展.

在21世纪初,Linux Torvalds提出了一种标志结构,用于确定执行模型的哪些组件共享以及执行分支时复制的内容,从而模糊了进程和线程之间的区别.从此,克隆呼叫出现了.

如果在那些线程中没有讨论过多的内存.设计目标是更多地控制fork的结果,而不是将内存使用优化委托给操作系统启发式,这是overcommit_memory = 0的默认设置.

注意事项

内存过量使用超出了这些扩展,增加了其模式2的权衡复杂性,设计趋势警告3,实际运行时限制4以及性能影响5.

便携性和长寿

此外,如果没有标准化,使用内存过量使用的代码可能不可移植,并且寿命问题是相关的,尤其是当设置控制函数的行为时.如果设置系统发生变化,则无法保证向后兼容,甚至无法保证某些情况.

危险

linuxdevcenter文档2说,“1总是过度使用.也许你现在意识到这种模式的危险.”,还有其他迹象表明总是过度使用6,7.

在LINUX,Windows和VMWare上过度使用的实施者可以保证可靠性,但它是一种统计游戏,结合过程控制的许多其他复杂性,可能在某些条件下导致某些不稳定的特性.甚至名称过度使用告诉我们它作为一种实践的真实性质.

一个非默认的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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读