1 进程与程序

在Linux系统中,执行一个程序或命令就可以触发一个进程,系统会给予这个进程一个ID,称为PID,同时根据触发这个进程的用户与相关属性关系,基于这个PID一组有效的权限设置。如下图所示(图片来自《鸟哥的Linux私房菜》[1]):

举个常见的例子,我们要操作系统的时候通常是利用ssh连接程序或直接在主机上登录,然后获取shell。默认的shell是bash,对应的路径为/bin/bash,那么同时间的每个人登录都是执行/bin/bash,不过每个人获取的权限不同,如下图所示:

也就是说,当我们的登录并执行/bin/bash程序时,系统已经给了我们一个PID,这个PID就是根据登陆者的UID/GID(/etc/passwd)而来,而所谓用户的权限就是这个bash进程的权限。当这个进程执行其它作业时,比如我们在shell中执行touch命令时,这个进程触发出来的其它进程也会沿用这个进程的相关权限

我们对程序与进程做一个总结:

  • 程序(program):通常为二进制程序,存储在存储媒介中(如磁盘等),以物理文件的形式存在。
  • 进程(process):程序被触发后,执行者的权限与属性、程序的代码与所需数据等都会被加载到内存中,操作系统给予这个内存中的单元一个标识符(PID),可以说进程就是一个正在运行中的程序

进程彼此之间是有关系的。从下图来看,连续执行两个bash后,第二个bash的父进程就是前一个bash,通过Parent PID(PPID)可获取其父进程的PID:

此外,子进程可以获取父进程的环境变量。

下面这个例子我们会展示子进程和父进程的关系。我们在当前的bash环境下,再触发一次bash,并用ps -l命令查看进程相关的输出信息,

bash-3.2$ ps -l
UID PID PPID F CPU PRI NI SZ RSS WCHAN S ADDR TTY TIME CMD
501 9892 9827 4006 0 31 0 408650672 1968 - S 0 ttys001 0:00.01 /bin/bash
501 9905 9892 4006 0 31 0 408657840 2736 - S 0 ttys001 0:00.01 /bin/bash

可以看到第一个bash的PID和第二个bash的PPID都是9892,这是因为第二个bash是来自第一个所产生的。

很多常常会发现,“咦,我们们将有问题的进程关闭了(比如Ctrl+C杀掉),怎么过一阵子它又自动产生了?而且新产生进程的PID还与原先不同这是怎么回事呢?”如果不是crontab计划任务的影响,那么肯定有一个父进程存在,所以我们杀掉子进程后,父进程又会主动再生成一个。那怎么办呢?“擒贼先擒王”。我们用ps auxf找出那个父进程,然后将它杀掉即可(后文会提到)。

fork and exec:进程调用的流程

子进程和父进程之间的关系比较复杂,最大的复杂点在于进程之间的调用。Linux程序的调用通常称为fork-and-exec流程。进程都会借由父进程以复制(fork)的方式产生一个一模一样的子进程,然后被复制出来的子进程再以exec的方式来执行时机要执行的代码,最终就成为一个子进程。整个流程有点像下面这张图:

  • 系统先以fork的方式复制一个与父进程相同的临时进程,这个进程与父进程唯一的差别就是PID不同,但这个临时进程还会多一个PPID参数。
  • 然后临时进程开始以exec的方式加载实际要执行的进程。以上图来讲,新的程序名称为qqq,最终子进程的进程代码就会变成qqq了。

系统或网络服务:常驻在内存里的进程

一般的Linux命令(如lstouchrm等)都是执行完就结束,也就是说该项命令被触发后所产生的PID很快就会被终止,那么有没有一直在执行的进程呢?

当然有,我们把在后台启动并一直持续不断地运行,也即常驻在内存当中的进程称为守护进程(daemon)。常见的服务包括系统本身所需要的服务(例如crond、atd、rsyslogd等)和负责网络连接的服务(例如apache、named、postfix、vsftpd等)。网络服务比较有趣的地方在于,它会启动一个可以复杂网络监听的端口(port),以提供外部客户端(client)的连接请求。

PS1:在Linux系统中,一般daemon类型的进程都会在文件名后面加上d。

PS2:“守护进程”这个概念由麻省理工学院MAC项目的程序员发明。费南多·柯巴托于1963年在MAC项目任务。根据他的说法,他的团队最早采用daemon这个概念,其灵感来源于麦克斯韦妖——一种物理学和热力学中虚构的介质,能帮助排列分子。他对此表示:“我们别出心裁地开始使用daemon这个词来描述后台进程,它们不知疲倦地处理系统中的杂务。”Unix系统继承了这个术语。作为一种在后台起作用的超自然存在,麦克斯韦妖与古希腊神话中的代蒙一致[2]。关于麦克斯韦妖的更多有趣信息可以参见梅拉妮·米歇尔的《复杂》[3]一书。

2 进程管理

想要查看系统上正在运行中的进程,可以利用静态的ps或者是动态的top命令,还可以利用pstree来查看进程树之间的关系。

ps:将某个时间点的进程运行情况撷取下来

ps aux可查看系统中所有的进程(注意,没有-号):

~/Orion-Orion # ps -aux                                                                                         root@qi
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4504 48 pts/0 Ss 2022 0:01 sh /root/start.sh
root 7 0.0 0.0 65520 420 ? Ss 2022 0:07 /usr/sbin/sshd
root 8 0.0 0.0 20052 264 pts/0 S+ 2022 0:00 /bin/bash
...
root 39717 0.1 0.0 93648 7608 ? Ss 08:40 0:02 sshd: root@notty
root 39727 0.0 0.0 9752 2924 ? Ss 08:40 0:00 bash
root 40140 0.5 0.0 95296 9220 ? Rs 08:54 0:02 sshd: root@notty
root 40150 0.0 0.0 9752 2832 ? Ss 08:54 0:00 bash

ps -l则可以仅查看自己的bash相关的进程:

~/Orion-Orion # ps -l                                                                                           root@qi
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 0 42331 41909 0 80 0 - 5015 wait pts/312 00:00:00 bash
0 R 0 42379 42331 0 80 0 - 6920 - pts/312 00:00:00 ps

我们可以看到,系统整体运行的进程是非常多的,但使用ps -l仅会列出与你的操作环境(bash)有关的进程,即最上层的父进程会是你自己的bash而没有扩展到systemd(后续会介绍)这个进程中。我们接下来来看看ps -l显示出来的数据有哪些?

  • F:表示这个进程标识(process flags),说明这个进程的权限,常见号码有:

    • 若为4表示此进程的权限为root。
    • 若为表示此进程仅执行复制(fork)而没有实际执行(exec)。
    • 若为0表示进程标识没有设置。
  • S: 代表这个进程的状态(STAT),主要的状态有:
    • R(Running):该进程正在运行中(running) 或是可运行的(runnable)
    • S(Sleep):进程处于可被唤醒(signal)的睡眠状态,也即所谓空闲状态(idle)。这种状态一般是进程主动进入的。
    • D:进程处于不可被唤醒的睡眠状态,通常这个进程可能在等待I/O的情况(例如打印)。这种状态一般是进程被动进入的。
    • T(Stopped)停止状态,可能是在任务控制(后台暂停)或跟踪(traced)状态。
    • Z(Zombie)僵尸状态(即所谓defunct),进程已经终止但却无法被删除至内存外。
  • UID/PID/PPID:代表进程被该UID所拥有/进程的PID号码/此进程的父进程PID号码。
  • C:代表CPU使用率,单位为百分比。
  • PRI/NI:Priority/Nice的缩写,代表此进程被CPU所执行的优先级,数值越小代表该进程越快被CPU执行。详细的PRI与NI将在下一小节说明。
  • ADDR/SZ/WCHAN:都与内存相关,ADDR是kernel function,指出该进程在内存的哪个部分,如果是个running的进程,一般就会显示-;SZ代表此进程用掉多少内存;WCHAN表示目前进场是否运行,同样的,若为-表示正在运行中。
  • TTY:登录者的终端位置,若为远程登录则使用动态终端接口名称(pts/n)。
  • TIME:使用CPU的时间,注意是进程实际花费CPU的时间,而不是运行时间。关于这两个时间之间的区别可参见我的博客《Python:对程序做性能分析及计时统计》
  • CMD:就是command的缩写,表示触发此进程的命令是什么。

所以你看到的ps -l输出信息中,它说明的是:bash进程属于UID为0的用户,状态为睡眠(Sleeping),之所以为睡眠,是因为它触发了ps(状态为Running)。此进程的PID是42331,执行优先顺序为80,执行bash所获取的终端接口为pts/0。运行状态为等待(wait)。

接下来我们用ps auxf列出类似进程树的进程显示:

(base) root@qi:~/Orion-Orion# ps -auxf
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4504 48 pts/0 Ss 2022 0:01 sh /root/start.sh
root 7 0.0 0.0 65520 420 ? Ss 2022 0:07 /usr/sbin/sshd
root 38677 0.0 0.0 93284 7412 ? Ss 07:55 0:00 \_ sshd: root@notty
root 38687 0.0 0.0 9756 2824 ? Ss 07:55 0:00 | \_ bash
root 38765 0.0 0.0 4504 1712 ? S 07:55 0:00 | \_ sh /root/.vscode-server/bin/b7886d7461186a5
root 41898 0.1 0.0 661960 58144 ? Sl 10:38 0:06 | | \_ /root/.vscode-server/bin/b7886d7461
root 42331 0.0 0.0 20060 3788 pts/312 S 10:40 0:00 | | \_ bash
root 43592 0.0 0.0 36276 3248 pts/312 R+ 11:41 0:00 | | \_ ps -auxf
...
root 39717 0.0 0.0 93648 7608 ? Ss 08:40 0:02 \_ sshd: root@notty
root 39727 0.0 0.0 9752 2924 ? Ss 08:40 0:00 | \_ bash
root 43493 0.0 0.0 4376 672 ? S 11:40 0:00 | \_ sleep 180
root 41362 0.0 0.0 93296 7360 ? Ss 10:33 0:01 \_ sshd: root@notty
root 41372 0.0 0.0 9752 2824 ? Ss 10:33 0:00 \_ bash
root 43492 0.0 0.0 4376 700 ? S 11:39 0:00 \_ sleep 180
root 8 0.0 0.0 20052 264 pts/0 S+ 2022 0:00 /bin/bash

因为我是用ssh网络连接进入服务器来执行一些测试的,可以看出进程之间是相关性的。从上面的例子来看,我是通过sshd提供的网络服务获取的一个进程,该进程提供bash给我使用,而我通过bash再去执行VSCode-Server服务启动脚本,以运行VSCode-Server服务进程,然后该进程再提供给我一个bash, 我通过这个bash再去执行ps auxf(疯狂套娃哈哈哈)。

这里说一个题外话,sshd进程是我们前面提到的deamon,是不能随意杀掉的哦! 杀掉了不仅你会马上断开连接,下次再用ssh连你也连不上了。

除了f这个选项,我们还可以使用pstree来完全查看这个进程树。

(base) root@qi:~/Orion-Orion# pstree
sh─┬─bash
└─sshd─┬─sshd───bash─┬─sh───node─┬─node───12*[{node}]
│ │ ├─node─┬─node───10*[{node}]
│ │ │ ├─node───11*[{node}]
│ │ │ ├─python───{python}
│ │ │ └─11*[{node}]
│ │ ├─node───11*[{node}]
│ │ ├─node─┬─bash───pstree
│ │ │ └─11*[{node}]
│ │ └─10*[{node}]
│ └─sleep
└─2*[sshd───bash───sleep]

除此之外,我们必须要知道的是僵尸(zombie) 进程是什么?通常,造成僵尸进程的原因在于该进程应该已经执行完毕,或是应该要终止了,但该进程的父进程却无法完整地将该进程结束掉,而造成该进程一直存在内存中。如果你发现在某个进程的CMD/COMMAND后面接上了defunct时,就代表该进程是僵尸进程,例如:

apache  8683  0.0  0.9 83384 9992 ?   Z  14:33   0:00 /usr/sbin/httpd <defunct>

系统不稳定的时候就容易造成所谓的僵尸进程,可能是因为程序写得不好,或是用户的操作习惯不良等所造成的。如果你发现系统中有很多僵尸进程时,记得要找出该进程的父进程,然后好好做个追踪,好好进行主机的环境优化,看看有什么地方需要改善,而不是直接将它kill掉。不然万一它一直产生就麻烦了。

事实上,通常僵尸进程都已经无法管理,而直接交给 systemd 这个进程来负责,偏偏systemd是系统第一个执行的进程,它是所有进程的父进程。我们是无法杀掉该进程的(杀掉它,系统就死掉了),所以如果产生僵尸进程,而系统过了一阵子还没有办法通过内核非经常性的特殊处理来将该进程删除时,那你只好通过reboot的方式来将该进程kill掉。

systemd是目前Linux系统上主要的系统守护进程管理工具,由于init一方面对于进程的管理是串行化的,容易出现阻塞情况,另一方面init也仅仅是执行启动脚本,并不能对服务本身进行更多的管理。所以最新系统(RedHat7,CentOS7,Ubuntu15…)大都由systemd取代了init作为默认的系统进程管理工具。

top:动态查看进程的变化

相对于ps是选取一个时间点的进程状态,top可以持续监测进程运行的状态,使用方式如下:

top [-d 数字] | top [-bnp]

它的选项与参数如下:

  • -d:后面可以接秒数,就是整个进程界面更新的秒数,默认是5秒。
  • -b:以批量的方式执行top,还有更多的参数可以使用,通常会搭配数据重定向来将批量的结果输出为文件。
  • -n:与-b搭配,意义是需要执行几次top的输出结果。
  • -p:指定某些PID来执行查看检测。

top的执行过程中可以使用下列的按键命令:

  • ?:显示在top中可以输入的按键命令
  • P:以CPU的使用排序显示。
  • M:以Memory的使用排序显示。
  • N:以PID来排序。
  • T:由该进程使用的CPU时间累积(TIME+)排序
  • k:给予某个PID一个信号(signal)。
  • r:给予某个PID重新制定一个nice值。
  • q:退出top的按键。

接下来我们实际查看一下如何使用toptop的界面。比如以下是我们输入top -d 2命令得到的结果,该命令表示每两秒钟更新一次top,查看整体信息。

top - 13:19:06 up 202 days,  5:00,  3 users,  load average: 89.81, 75.65, 68.67
Tasks: 74 total, 1 running, 73 sleeping, 0 stopped, 0 zombie
%Cpu(s): 32.2 us, 4.5 sy, 35.7 ni, 27.5 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st
KiB Mem : 52701926+total, 52750784 free, 49904712 used, 42436377+buff/cache
KiB Swap: 8388604 total, 7983868 free, 404736 used. 46639996+avail Mem
<==如果加入k或r时,就会有相关的字样出现在这里。
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
38775 root 20 0 1106596 236232 37596 S 1.0 0.0 1:28.68 node
12191 root 20 0 1662128 61256 11176 S 0.5 0.0 205:36.04 python
1 root 20 0 4504 48 0 S 0.0 0.0 0:01.03 sh
7 root 20 0 65520 420 4 S 0.0 0.0 0:07.19 sshd
...
41787 root 20 0 20060 3700 32 S 0.0 0.0 0:00.01 bash
41898 root 20 0 968200 62276 33216 S 0.0 0.0 0:14.26 node

可见,topps的静态结果输出不同,top这个进程可以持续地监测整个系统的进程任务状态。在默认的情况下更新进程资源的时间为5秒,不过可以使用-d来执行修改。top主要分为两部分界面,上面的界面为整个系统的资源使用状态,基本上总共有六行。至于top下半部分的画面,则是每个进程使用的资源情况。

top默认使用CPU使用率(%CPU)作为排序的依据,如果你想要使用内存使用率排序,则可以按下M键,若要恢复则按下P键即可。如果想要退出top,则按下q

参考

Linux:进程模型和进程管理的更多相关文章

  1. Nginx学习——进程模型(master 进程)

    进程模型 Nginx分为Single和Master两种进程模型.Single模型即为单进程方式工作,具有较差的容错能力,不适合生产之用.Master模型即为一个master进程+N个worker进程的 ...

  2. linux进程模型总结

    Linux进程通过一个task_struct结构体描述,在linux/sched.h中定义,通过理解该结构,可更清楚的理解linux进程模型.       包含进程所有信息的task_struct数据 ...

  3. 第一次作业:基于Linux操作系统深入源码进程模型分析

    1.Linux操作系统的简易介绍 Linux系统一般有4个主要部分:内核.shell.文件系统和应用程序.内核.shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序.管理文件并使 ...

  4. Linux进程模型

    ----原文链接:http://www.cnblogs.com/biyeymyhjob/archive/2012/08/01/2617884.html------ Linux进程通过一个task_st ...

  5. Linux下0号进程的前世(init_task进程)今生(idle进程)----Linux进程的管理与调度(五)【转】

    前言 Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2) idle进程由系统自动创建, 运行在内核态 idle进程其pi ...

  6. Linux下的进程类别(内核线程、轻量级进程和用户进程)--Linux进程的管理与调度(四)

    本文中出现的,内核线程,轻量级进程,用户进程,用户线程等概念,如果不太熟悉, 可以参见 内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程) Linux进程类别 虽然我们在区分Linux ...

  7. linux C++ 通讯架构(一)nginx安装、目录、进程模型

    nginx是C语言开发的,号称并发处理百万级别的TCP连接,稳定,热部署(运行时升级),高度模块化设计,可以用C++开发. 一.安装和目录 1.1 前提 epoll,linux内核版本为2.6或以上 ...

  8. linux学习笔记4:linux的任务调度,进程管理,mysql的安装和使用,ssh工具的使用,linux网络编程

    1.设置任务调度命令crontab 任务调度是指系统在某个时间执行的特定的命令或程序.任务调度分为:1)系统工作:有些重要的工作必须周而复始的执行,如病毒扫描.2)个别用户工作:个别用户可能希望执行某 ...

  9. Linux第九讲随笔 -进程管理 、ps aux 、

    Linux第九讲1,进程管理 Linux在执行每一个程序时,就会在内存中为这个程序建立一个进程,以便让内核可以管理这个运行中的进程,进程是系统分配各种资源,进程调度的基本单位. 怎么查看进程 一.ps ...

  10. Linux操作系统进程模型分析进程

    Linux操作系统简介 Linux拥有现代操作系统的功能,如真正的抢先式多任务处理,支持多用户内存,保护虚拟内存,支持SMP.UP,符合POSIX 标准联网.图形用户接口和桌面环境具有快速性.稳定性等 ...

随机推荐

  1. JNI接口的实现

    JNI接口的实现 什么是JNI 说明:JNI 是 Java Native Interface 的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++,但是它并不妨碍你使用 ...

  2. vue上传图片组件

      <template> <!-- 上传控件 用法: <upload-widget v-model="imgUrl"></upload-widg ...

  3. Python爬虫iP被封的怎么办?

    对于经常做数据爬虫的程序员来说,除了要写出简洁方便的代码.还需要解决的是网站反爬的问题.有时候我们在爬取数据的时候突然报出错或者目标网站错误代码. 比如说:403 Forbidden错误," ...

  4. H5软键盘回车事件

    //软键盘回车事件 document.onkeydown = function (event) { var e = event || window.event; if (e.keyCode === 1 ...

  5. ddddd

    项目二阶段总结 账户微服务 短信发送 1.压测发现问题 首先对短信smscomponent的send方法在test单元测试类中测试,不是真的发短信测试,可以建立请求开始和结束的时间戳来确定请求的耗时. ...

  6. 【基础知识】C++算法基础(快速排序)

    快速排序: 1.执行流程(一趟快排): 2.一趟快排的结果:获得一个枢纽,在此左边皆小于此数,在此右边皆大于此数,因此可以继续使用递归获得最终的序列.

  7. DBEditEh/Edit 文本框内容空白时加上提示文字,输入内容时提示文字不显示

    当文本框没有输入内容且输入焦点不在文本框时,显示提示文字:"请输入帐号"当文本框得到输入焦点时提示文字不显示 unit SkinHintEdit; interface uses W ...

  8. tensorflow的断点续训

    tensorflow的断点续训 2019-09-07 顾名思义,断点续训的意思是因为某些原因模型还没有训练完成就被中断,下一次训练可以在上一次训练的基础上继续训练而不用从头开始:这种方式对于你那些训练 ...

  9. Linux子系统之【内存管理】

    1.内存管理的意义? 内存是进程运行的地方,相当于是战场.完善的机制能让进程多快好省地运行. 2.原始内存管理是怎么样的? 简陋(直接运行在物理内存上).不安全(无隔离,无权限) 缺点:容易出错,进程 ...

  10. R grep

    SAIN<-FAIN[grepl("HE-H$",FAIN$rDD),,drop=TRUE]