我们知道,Bash 在执行一个外部命令时,会先 fork() 一个子进程,然后在子进程里面执行 execve() 去加载那个外部程序。fork 子进程是会耗性能的,所以 Bash 会在下面几种情况下不 fork 子进程,直接在当前进程执行 execve()。

bash -c 'command'

如果用了 bash -c 的形式启动 Bash,同时 -c 选项的参数里只包含一个命令,比如 bash -c 'sleep 666',这时 Bash 不会 fork 子进程去运行 sleep 命令,它会让 sleep 直接占用自己现有的进程:

$ bash -c 'sleep 666' &

$ pstree -ap

...

|  `-bash,3117

|      |-pstree,3119 -ap

|      `-sleep,3118 666

...

3117 是我当前敲入命令的交互 Shell,3118 就是 bash -c 启动的那个进程,然后直接被替换成了 sleep,pid 还是 3118。

我们可以看一下 Bash 无法优化的情况下,进程树是什么样的:

$ bash -c 'sleep 666;ls' &

$ pstree -ap

...

|  `-bash,3117

|      |-bash,3120 -c sleep\040666;ls

|      |   `-sleep,3121 666

|      `-pstree,3122 -ap

...

这次我们给 -c 的参数包含了两个命令,sleep 和 ls,所以 Bash 不能让 sleep 占用它的进程,因为执行完 sleep 它还得去执行 ls。

bash -c 'command1 && command2 || command3 ... && commandN'

在这种由若干个 && 和 || 把若干个简单命令组成的的复合命令中,最右侧的那个(commandN)命令执行时(如果执行到的话)会进行 no-fork 优化:

$ bash -c 'sleep 1 || sleep 2 && sleep 666' &

$ pstree -ap # 等 3 秒钟后再执行这条

...

|  `-bash,3117

|      |-pstree,3126 -ap

|      `-sleep,3123 666

...

在 bash -c 'sleep 1 || sleep 2 && sleep 666' 这条命令中,一共产生过 3 个进程,bash -c 首先产生了一个进程 3123,然后 3123 又分别 fork 出两个子进程 3124 和 3125 来分别执行 sleep 1 和 sleep 2,sleep 666 没有产生新的进程,它和 bash -c 用了同一个进程,也就是 3123。这个优化在 Bash 4.4 之前没有。

( command )

用显示的子 shell 语法运行一个单独的命令,比如 ( sleep 100 ),如果不进行优化的话,这里应该先 fork 一个子 shell,然后这个子 shell 会再 fork 一个子子 shell 去运行 sleep,一共 fork 两次,再极端点:( ( ( ( ( sleep 100 ) ) ) ) ),会产生一个 5 级的子 shell(( ( ( ( ( echo $BASH_SUBSHELL ) ) ) ) ) 的确会输出 5),一共 fork 6次,然而 Bash 并不会这样做,无论你嵌套了多少级,Bash 只会 fork 一次,只产生一个子进程,然后在这个进程里执行 sleep 命令。

Bash 的 no-fork 优化的更多相关文章

  1. fork炸弹

    众所周知,bash是一款极其强大的shell,提供了强大的交互与编程功能.这样的一款shell中自然不会缺少“函数”这个元素来帮助程序进行 模块化的高效开发与管理.于是产生了由于其特殊的特性,bash ...

  2. Bash 的若干基本问题

    Bash 的若干基本问题   这里介绍一些bash启动前.后的问题,以及一些使用bash需要注意的基本问题.     1.Bash的介绍   Bash是一种Shell程序,它是一般的Linux系统中的 ...

  3. Linux基础优化与安全归纳总结

    一名运维工程师在运维岗位上时间久了,就会发现Linux优化的重要性,同时会给运维工作带来很多的便利性.本人逐渐认识到了这一点,所以特意在工作闲暇之余,通过阅读Linux相关书籍及向同事.同行高手咨询, ...

  4. 总结linux内核的一些参数优化

    sysctl命令被用于在动态地修改内核的运行参数,可用的内核参数在目录/proc/sys中. 它包含一些TCP/IP堆栈和虚拟内存系统的高级选项, 用sysctl可以读取设置超过五百个系统变量. sy ...

  5. linux进程管理(上)

    程序和进程的区别: 1.程序是一种静态资源 程序启动产生进程 2.程序与进程无一一对应原则  进程是动态的一个过程 父进程和子进程在前面提过 前台进程:执行命令时只能等待的进程为前台进程也叫异步进程 ...

  6. Ubuntu检测磁盘是否挂载

    Ubuntu默认不自动挂载磁盘. 只是学习Bash使用,需优化如使用 # file: mountAll.sh # include color support # a list of variables ...

  7. 实现mypwd和mybash

    一.pwd 1.学习pwd命令 man pwd查看pwd功能 可以得知pwd功能是打印当前目录 2.研究pwd实现需要的系统调用(man -k; grep),写出伪代码 (1)man -k direc ...

  8. Linux 用户身份与进程权限

    在学习 Linux 系统权限相关的主题时,我们首先关注的基本都是文件的 ugo 权限.ugo 权限信息是文件的属性,它指明了用户与文件之间的关系.但是真正操作文件的却是进程,也就是说用户所拥有的文件访 ...

  9. Linux进程的原理及与信号的联系

    第1节 程序.进程.守护进程.僵尸进程的区别 程序.进程.守护进程.僵尸进程: 程序:c/php/java,代码文件,静态的,放在磁盘里的数据. 进程:正在内存中运行的程序,进程是动态的,会申请和使用 ...

随机推荐

  1. Python class and function json

    # coding=utf-8 __author__ = 'student' ''' how to define a class how to extend a class how to make a ...

  2. 理解 OpenStack + Ceph (9): Ceph 的size/min_size/choose/chooseleaf/scrubbing/repair 等概念

    本系列文章会深入研究 Ceph 以及 Ceph 和 OpenStack 的集成: (1)安装和部署 (2)Ceph RBD 接口和工具 (3)Ceph 物理和逻辑结构 (4)Ceph 的基础数据结构 ...

  3. 前端构建工具gulp使用

    前端自动化流程工具,用来合并文件,压缩等. Gulp官网 http://gulpjs.com/ Gulp中文网 http://www.gulpjs.com.cn/ Gulp中文文档 https://g ...

  4. JAVA类的静态加载和动态加载以及NoClassDefFoundError和ClassNotFoundException

    我们都知道Java初始化一个类的时候可以用new 操作符来初始化, 也可通过Class.forName()的方式来得到一个Class类型的实例,然后通过这个Class类型的实例的newInstance ...

  5. 关于selenium的CI、框架……

    这段时间除了项目测试外,主要在做web自动化的事情,大致总结一下吧,总体的设计模式pageobject+pagefactory+testng的数据驱动,项目用maven来构建,使用jenkins集成, ...

  6. POJ2794 Double Patience[离散概率 状压DP]

    Double Patience Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 694   Accepted: 368 Cas ...

  7. 微信接口-获取用户openid基本信息

    一.协助获取微信用户openid功能 https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri= ...

  8. 四校联考 tree3

    我们考虑计算红色点与非红色点的对数. 我们用f[i][j]表示i的子树中有j个红色点的概率,将i所有子树合并. 接着我们对于每一个状态,枚举i是红色还是非红色算概率. 同时我们可以求出i和i子树内一个 ...

  9. PHP开发环境搭建

    链接: Q&A1.Mac下的PHP环境搭建 Mac 下如何搭建 PHP 开发环境? [PHP] Mac下homebrew安装及php.mysql.nginx环境安装及配置个人PHP开发环境的选 ...

  10. C#多维数组与嵌套数组

    using System; namespace abc.e.f//等价于下面分层嵌套的写法.且这种写法不管命名空间abc有没有定义过,也不管命名空间e有没有定义过 { class MYTestX { ...