我们知道,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. HDU 5183 Negative and Positive (NP) --Hashmap

    题意:问有没有数对(i,j)(0<=i<=j<n),使得a[i]-a[i+1]+...+(-1)^(j-i)a[j]为K. 解法:两种方法,枚举起点或者枚举终点. 先保存前缀和:a1 ...

  2. 洛谷10月月赛Round.3

    Rank11:260=60+100+100 P2409 Y的积木 题目背景 Y是个大建筑师,他总能用最简单的积木拼出最有创意的造型. 题目描述 Y手上有n盒积木,每个积木有个重量.现在他想从每盒积木中 ...

  3. 洛谷U4859matrix[单调栈]

    题目描述 给一个元素均为正整数的矩阵,上升矩阵的定义为矩阵中每行.每列都是严格递增的. 求给定矩阵中上升子矩阵的数量. 输入输出格式 输入格式: 第一行两个正整数n.m,表示矩阵的行数.列数. 接下来 ...

  4. Fullscreen API 全屏显示网页

    可参考文档:http://blog.csdn.net/tywali/article/details/8623938 脚本代码 <script type="text/javascript ...

  5. AndroidStudio导入Eclipse的代码格式化文件

    对于一个团队来说,使用统一的代码格式是非常重要的,否则在使用版本控制工具时,会出现大量的冲突.在Eclipse里,我们可以通过一些xml来进行代码格式的统一,但是这些文件要应用在AndroidStud ...

  6. 疑难杂症——EF+Automapper引发的查询效率问题解析

    前言:前面总结了一些WebApi里面常见问题的解决方案,本来打算来分享下oData+WebApi的使用方式的,奈何被工作所困,只能将此往后推了.今天先来看看EF和AutoMapper联合使用的一个问题 ...

  7. HTTPS 原理解析

    一 前言 在说HTTPS之前先说说什么是HTTP,HTTP就是我们平时浏览网页时候使用的一种协议.HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全.为了保证 ...

  8. 关于把.net 2.0的项目升级到.net4.0遇到的一些问题

    进入公司实习的的第一个项目又是是一个升级项目.这次升级的是一个c/s架构的项目. 大致介绍一下这个项目的结构客户端采用winform+devexpress商业控件开发的,数据库是用的oracle数据库 ...

  9. 奇虎360诉腾讯QQ垄断案之我见(3Q大战之我见)

    这两款软件我都在用,要说时间最长感情最深的应该是腾讯QQ,1999年诞生的那年就在用QQ了! 不过感情归感情,个人看法归个人看法,不能用感情来判断. 正所谓外行看热闹,内行看门道.从事实上讲在使用这两 ...

  10. C# double 四舍五入

    public static double Round(object data) { if (data == null || data == System.DBNull.Value) { return ...