Linux学习之进程和资源管理

HyriKuma

总结Linux下进程和资源相关的概念,并利用相关Linux命令对其进查看管理。

1. 理解进程的概念

在Linux中,进程是程序执行的实例,它包含了程序的代码和执行时的数据及状态,是随着程序被加载内存中运行而产生的。对于Linux系统来说进程是资源封装的单位,其占用了内存、磁盘、PID、网络、CPU等系统资源。当程序被执行产生进程,系统将自动为进程赋予一个PID,并给启动这个进程的用户予以一组有效的权限设置。

1.1 父子进程的概念

父子进程指的是通过进程创建机制所产生的相关联的两个进程。在Linux系统中,父进程通过系统调用fork()来创建子进程,子进程会继承父进程的资源和状态,能够独立于父进程执行新的程序。

比如,当通过ssh连接到远程Linux系统时,通常会触发作为父进程的sshd守护进程创建一个新的sshd子进程,用作接受处理ssh客户端(如Xshell)的新请求,当ssh连接成功建立,此时sshd作为父进程将会为连接的用户创建一个bash的子进程,用于处理用户输入执行的命令,而当用户在bash shell上输入并执行命令时,bash shell又会创建一个新的子进程来负责命令的处理。这里可以同时使用多个终端进行ssh连接,然后执行不同命令,然后使用pstree | grep sshd来获取sshd父子进程的树状关系。

1
2
3
4
5
$ pstree | grep sshd

|-sshd-+-sshd---sshd---bash---htop
| |-sshd---sshd---bash-+-grep
| `-sshd---sshd---bash---tail

用图表可以直观描述为

graph LR
    sshd守护进程 --> |fork| 1[sshd子进程]
    sshd守护进程 --> |fork| 2[sshd子进程]
    sshd守护进程 --> |fork| 3[sshd子进程]
    1[sshd子进程] --> |fork| 4[bash解释器]
    4[bash解释器] --> |fork| htop命令
    2[sshd子进程] --> |fork| 5[bash解释器]
    3[sshd子进程] --> |fork| 6[bash解释器]
    5[bash解释器] --> |fork| grep命令
    6[bash解释器] --> |fork| tail命令
    6[bash解释器] --> |fork| 9[...]

1.2 进程的生命周期

正常的进程生命周期分为几个关键的阶段,主要有创建、就绪、运行、阻塞、终止五个阶段。当一个进程通过fork()被创建出来时,系统会为新的进程分配一个新的PID用作标识该进程,并为进程分配系统资源,完成进程的创建初始化后进入到就绪状态,此时进程的资源已经分配完成,只需要获得CPU的资源调度即可进入到运行状态。而当进程因为某些事件发生而导致无法执行时,此时进程由运行状态转为阻塞状态,阻塞状态的进程当完成资源的重新分配及请求通过后,又会被唤醒为就绪状态等待CPU资源的调度。最后当进程完成任务后,进程进入终止阶段,系统将调用exit()来终止进程并释放所有资源。

graph LR
    创建阶段 --> |初始化完成| 就绪阶段
    就绪阶段 --> |CPU调度| 运行阶段
    运行阶段 --> |事件中断| 阻塞阶段
    阻塞阶段 --> |重新唤醒| 就绪阶段
    运行阶段 --> |任务完成| 终止阶段
    终止阶段 --> |释放资源| 资源回收

1.3 孤儿进程和僵尸进程

  • 孤儿进程

孤儿进程,即当父进程提前终止时,子进程仍处在运行或者其他阶段时的进程状态,此时子进程将会成为孤儿进程。为了避免子进程在执行完成后无法释放资源而导致非正常终止的情况发生,在Linux系统中,孤儿进程通常会被PID为1的init系统守护进程接管充当其父进程,直到子进程任务执行完成将资源正常释放。

graph TD
    init进程 --> 父进程
    父进程 --> 子进程
    父进程 --> |提前终止| 资源回收
    init进程 --> |接管| 子进程
    子进程 --> |执行完成| 资源回收
  • 僵尸进程

正常情况下,当子进程执行完成后,通过调用exit()进入到终止状态,然后让父进程进行wait()的系统调用来获取子进程的终止状态,一旦子进程的终止状态被系统调用读取,子进程的资源也就被系统回收,其PID和相关信息也将从进程表中移除。而如果当子进程执行完成进入终止状态,父进程却没有及时回收子进程的终止状态,此时子进程的程序资源虽然已经被系统回收,但仍然滞停在终止状态,占用着进程表的PID和信息描述等资源,这种状态就叫做僵尸进程状态。

graph TD   
    父进程初始化 ----> 父进程
    父进程 ---> 父进程终止
    父进程 --> |fork| 子进程初始化
    subgraph child_process 
    子进程初始化 --> 子进程
    子进程 ---> |exit| 子进程终止
    end
    子进程终止 --> |wait| 父进程
    子进程终止 ----> |父进程未回收| 僵尸进程

2. 进程管理

在Linux中,要想查看各进程信息和状态,常用的是ps命令,即process status,能够显示当前运行在系统中的进程快照,常用选项有e-f-l等。比如

1
2
3
4
ps -ef #以完整格式显示当前所有进程的信息
ps -l #以长格式显示进程信息
ps -u username #查看指定用户的进程信息
ps aux #类似于ps -ef,显示风格不同

比如要获取nginx进程的详细状态信息,可以结合grep执行

1
ps -ef | grep nginx 

得到返回

1
2
3
4
5
6
7
root      137746       1  0 11:34 ?        00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data 137747 137746 0 11:34 ? 00:00:00 nginx: worker process
azureus+ 138618 138466 0 14:31 pts/0 00:00:00 grep --color=auto nginx

分别对应

用户 进程PID 父进程PPID CPU使用率 进程启动时间 关联终端 累计使用CPU时间 进程命令

而想要结束进程,可以使用killpkill,并搭配一些信号参数来实现。

1
2
kill PID #通过PID来杀死进程
pkill process_name #通过进程名来杀死进程

一些常用的信号参数有

1
2
3
-15 #默认参数,令进程正常终止
-9 #强制终止进程
-1 #挂起信号,令进程重新加载配置文件或重启

另外还可以使用一些常用的命令和符号对进程进行前后台管理

1
2
3
4
nohup command & #令command命令在后台运行,而且不受终端关闭的影响
fg %[jobs id] #将后台进程转到前台,注意不是PID
bg %[jobs id] #将前台进程转到后台,注意不是PID
jobs -l #查看后台进程的状态信息

3. 资源管理

3.1 实时整体资源监视

如果要查看系统整体的实时资源情况,如CPU实时利用率,内存使用情况,实时进程列表等状态,可以输入top来进行快速了解,top能提供一个交互式的界面供用户查看和和过滤显示。

这里首先可以看到当前时间和登录的用户数,后面的load average: 0.00, 0.01, 0.00分别代表在一分钟内、五分钟内、十五分钟内系统的平均负载。然后是实时任务数量,包括各状态(运行中、休眠、终止、僵尸状态)任务的显示。而%Cpu(s)即为CPU使用率的详细信息。接下来分别是内存和交换空间(与磁盘空间交换而来的虚拟内存)的实时信息,如内存总量、空闲内存情况、已使用空间等。最后是实时进程的详细信息,包括PID、启动用户、占用内存、使用CPU的百分比、累计占用CPU的时间等。

此外还有如htopglances这类类似于top的实时资源监视工具,同样可以直观地查看各系统资源的使用状况。

  • htop

  • glances

3.2 瞬时资源信息查看

  • CPU资源信息

要想查看CPU的详细架构和配置信息,可以使用lscpu命令,能够得到CPU架构型号、总核数、时钟频率等参数。

uptime能用于查看系统运行状态和平均负载,得到返回结果例如

1
2
3
11:34:23 up 14 days, 18:22,  2 users,  load average: 0.43, 0.11, 0.04

当前时间 运行时间 当前登录用户数 平均负载
  • 内存资源信息

如果要查看内存相关信息,可以选择free命令,搭配一些常用的选项-h-m-s等,例如

1
$ free -hs 5 #以五秒为间隔输出当前的内存瞬时状态,并以易读状态显示 

得到返回类似于top下的内存信息

1
2
3
               total        used        free      shared  buff/cache   available
Mem: 884Mi 343Mi 71Mi 3.0Mi 469Mi 360Mi
Swap: 0B 0B 0B
  • 磁盘资源信息

通过使用df命令搭配一些常用选项可以查看到文件系统的磁盘空间的使用情况

1
df -h #以易读方式显示磁盘使用情况

以其中一行为例,得到返回结果如

1
2
Filesystem      Size  Used Avail Use% Mounted on
/dev/root 62G 3.5G 59G 6% /

这表示文件系统为/dev/root的根文件系统,总容量为62GB,已使用空间为3.5GB,剩余可用空间为59GB,空间利用率为6%,文件系统的挂载点为/即根目录。

另外还可以使用lsblk来树状显示磁盘的块设备和分区的整体结构信息,得到返回结果如

1
2
3
4
5
6
7
8
9
10
11
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 63.5M 1 loop /snap/core20/2015
loop1 7:1 0 111.9M 1 loop /snap/lxd/24322
loop2 7:2 0 40.9M 1 loop /snap/snapd/20290
sda 8:0 0 64G 0 disk
├─sda1 8:1 0 63.9G 0 part /
├─sda14 8:14 0 4M 0 part
└─sda15 8:15 0 106M 0 part /boot/efi
sdb 8:16 0 4G 0 disk
└─sdb1 8:17 0 4G 0 part /mnt
sr0 11:0 1 628K 0 rom

返回信息包括了设备名,主次设备号,是否可读写和可移动,总容量大小,设备类型,挂载点这些信息。可以知道其中sdadisk即为磁盘类型,其下分别有三个磁盘分区,而sr0rom类型的只读光驱存储器。

  • 网络资源信息

可以采用netstatss来显示系统网络状态信息,比如执行

1
netstat -tunlp

这表示查看当前所有的TCP和UDP网络连接,以数字形式显示ip地址和端口及端口监听状态,并将每个和连接相关的进程及其PID显示出来。得到结果如

1
2
3
4
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 176089/nginx: maste
udp 0 0 127.0.0.53:53 0.0.0.0:* 47883/systemd-resol