我有一个可以占用4-8GB内存的大型服务器软件。
这使得fork-exec很麻烦,因为fork本身可能需要很长时间,而且默认行为似乎是fork会失败,除非有足够的内存用于整个驻留内存的副本。
因为在开始分析时,我开始表现为最热门的地方(60%的时间花在分叉上),我需要解决它。
避免fork-exec例程的最简单方法是什么?
答案 0 :(得分:6)
您基本上无法避免fork(2)(或等效的clone(2)系统调用...,或我不建议使用的过时vfork
)+ execve(2)启动Linux和(可能)MacOSX以及大多数其他Unix或POSIX系统上的外部命令(àlasystem(3)或àlaposix_spawn)。
是什么让你认为它正在成为一个问题?今天8GB进程虚拟地址空间并不是什么大问题(至少在8Gbytes或16GB内存的机器上,就像我的桌面一样)。由于所有最近的Unix使用的懒惰copy-on-write技术,你实际上并不需要两倍的RAM(但你确实需要交换空间)。 Linux操作系统。
也许您可能认为交换空间可能是一个问题。在Linux上,您可以通过交换文件来添加交换空间;只是以root身份运行:
dd if=/dev/zero of=/var/tmp/myswap bs=1M count=32768
mkswap /var/tmp/myswap
swapon /var/tmp/myswap
(当然,请确保/var/tmp/
不是tmpfs挂载的文件系统,但是它位于某个磁盘上,可能是SSD磁盘....)
如果您不再需要大量的交换空间,请运行swapoff /var/tmp/myswap
....
您也可以在程序开头附近启动一些外部shell进程(àlapopen
),稍后您可以向它发送shell命令。看看我的execicar.c程序获取灵感,或者如果它适合的话使用它(我10年前为了类似的目的写了它,但我忘记了细节)
或者在程序开头派一些解释器(Lua,Guile ...)并向其发送一些命令。
每秒运行几十个命令(启动任何外部程序)不合理,应该被视为设计错误,恕我直言。也许正在运行的命令可以被进程内函数替换(例如/bin/ls
可以使用stat
,readdir
,glob
函数 ...)。也许您可以考虑在代码中添加一些plugin能力(使用dlopen(3)& dlsym
)(并从插件运行函数,而不是经常启动程式)。或者在您的代码中嵌入一个解释器(Lua,Guile,...)。
例如,对于Web服务器,请查找旧CGI vs FastCGI或HTTP转发(例如URL redirection)或嵌入式PHP或{{3 }}或HOP
答案 1 :(得分:2)
这使得fork-exec很麻烦,因为fork本身可以使用 重要的时间
这只是一半。您没有指定操作系统,但fork(2)
在Linux中进行了相当优化(我相信其他UNIX变体),使用copy-on-write。写时复制意味着操作系统不会复制整个父内存地址空间,直到子(或父)写入内存。所以你可以放心,如果你有一个父进程使用8 GB内存然后你分叉,你将不会使用16 GB的内存 - 尤其是如果孩子立即执行()。
除非有足够的内存用于整个副本,否则fork将失败 居民记忆。
没有。 fork(2)
引起的唯一开销是为子进程复制和分配任务结构,分配PID以及复制父进程的页表。如果没有足够的内存来复制整个父地址空间,fork(2)
将不失败,如果没有足够的内存来分配新的任务结构和页表,它将失败。如果已达到用户的最大进程数,它也可能会失败。您可以在man 2 fork
中确认这一点(注意:请参阅下面的评论)。
如果您仍然不想使用fork(2)
,则可以使用vfork(2)
,它根本不复制 - 它甚至不复制页面表 - 所有内容都与父级共享。您可以使用它来创建一个具有可忽略的开销的新子进程,然后执行exec()。请注意vfork(2)
阻止调用线程,直到子进退或调用七个exec()函数之一。在调用任何exec()函数之前,也不应该修改子进程内的内存。
答案 2 :(得分:1)
您提到您每秒可以fork
+ exec
10k次。这听起来非常过分。你有没有考虑过让你exec
成为守护进程的东西?或者可以在应用程序中实现这些外部程序?这听起来非常狡猾。
fork
很可能开始失败,尽管有内存支持它,因为你的Linux已经禁用(或限制)内存过度使用。检查文件/proc/sys/vm/overcommit_memory
。如果它是1然后我的猜测是错误的,还有其他奇怪的事情发生。如果它是0那么你根本不允许过度使用。如果它是2那么你需要阅读文档以确定如何配置它。
上面提到的一个解决方案就是添加交换(永远不会被使用)。
另一个解决方案是实现一个小守护进程,该守护进程将接受命令并执行那些forks和exec,以便为您提供所需的输出。
N.B。理论上,fork
一个大型过程可以像一个小过程一样快。 fork的性能取决于你拥有多少内存映射,而不是它们覆盖的内存量。根据映射设置写时复制。除了在某些操作系统上设置匿名映射的COW与这些映射中的内存量呈线性关系,但我不知道Linux在这里做了什么,上次我在Linux上研究VM系统已超过15年了。