我有一个要求。我的进程必须在其代码路径之一中执行另一个进程。子进程运行一些检查,当某些条件为真时,它必须重新执行。当我在高端机器上测试时,它没有引起任何性能问题。
但是在同一个进程中再次调用execv()会很昂贵吗?特别是当它自己执行时?
注意:第二次没有涉及fork()。该过程将第二次execv()本身,以在其虚拟地址空间中重新映射。
答案 0 :(得分:4)
第二次execv()
电话并不比第一次更贵。它甚至可能更便宜,因为系统可能不需要从磁盘读取程序映像,也不需要加载任何新的动态库。
另一方面,execv()
只需在同一程序中进行分支即可。我无法想象一种情况,我想写一个重新执行自己的程序(没有分叉),而不是仅仅调用一个函数。
第三方面,"便宜"并且"昂贵"是相对的。除非你这么做很多,否则你可能实际上没有注意到任何差异。
答案 1 :(得分:4)
execve
系统调用有点贵;运行它超过几十次 - 或者每秒几百次(即使它可能持续几毫秒,也许大部分时间可能只有几分之一毫秒)是不合理的。
它可能比你用来mmap(2)(& munmap
& mprotect(2)}和setcontext(3)的十几个等效来电更快(更干净) 几乎模仿它(然后,有一个问题是在执行execve
的人之外杀死正在运行的线程,以及附加到进程的其他资源,例如FD_CLOEXEC
- ed文件描述符)。
(您将无法复制mmap
,munmap
,setcontext
,close
正是execve
正在做的事情,但是你可能足够接近......但这太荒谬了)
此外,execve
的实际成本还应考虑共享库的动态加载(应在运行main
之前加载),但技术上 execve
系统调用...)及其启动后。
问题可能并不多,这在很大程度上取决于机器的实际状态和execve
ed executabe。我猜execve
是一个巨大的ELF二进制文件(一些可执行文件可能有一个千兆字节的代码段,例如传说神秘的Google爬虫可能是一个单片程序,有十亿个C ++源代码行,在某些时候它是静态链接),例如数百个共享库比execve
要长/bin/sh
。
我想同时,来自具有TB级地址空间的进程的execve
比我execve
我的zsh
shell在我的桌面上执行的时间要长得多。
execve
自己的程序(实际上是它的一些更新版本)的一个典型原因是,在一个持久的服务器中,当服务器的二进制可执行文件已经更新时。
execve
自己的程序的另一个原因是让一个或多或少的“无状态”服务器(一些用于静态内容的Web服务器)重新启动并重新加载其配置文件。
更一般地说,这是一个完整的研究主题:阅读dynamic software updating,application checkpointing,persistence等...另请参阅参考文献here。
转储core(5)文件是一样的:在我的生活中,我从来没有看到核心转储持续时间超过一秒钟,但我确实听说过比1990年代早期的Cray计算机, core
转储可能(病理上)持续半小时......所以我想一些病态的execve
可能会持续相当长的时间(例如,使用C-O-W带来一个TB的代码段RAM中的技术;这不算作execve
时间,但它是启动程序的成本的一部分;并且您可能还有许多共享库的重定位。)。
对于一个小的可执行文件(少于几兆字节),你可能每秒可以承受几百execve
个,所以这在实践中并不是什么大问题。请注意,使用ls
,mv
等常用命令的shell脚本是execve
- 非常多(通常在fork
之后,它会为几乎所有命令)。如果您怀疑某些问题,可以进行基准测试(例如使用strace -tt -T -f
使用strace(1) ....在我的桌面上Debian / x86-64 / Sid i7 3770K execve
/bin/ls
(strace --T -f -tt zsh-static -c ls
}大约需要250μs(对于ELF二进制文件executable /bin/ls
的118K字节(可能已经在page cache中),而ocamlc
(1.8Mbyte的二进制)约为1.3ms; a malloc
通常需要一半或几μs;对time(2)的调用大约需要3ns(通过vdso(7)来避免系统调用的开销......)