进程基本概述
程序与进程
- 什么是程序:开发编写的源代码,封装为产品,比如(微信、钉钉等等)都称为程序
- 什么是进程:程序运行的过程,我们称为进程,它主要是用来控制计算机硬件运行我们的程序
- 程序与进程区别:
- 程序:程序是数据+指令的集合,是一个静态的概念,同时程序可以长期存在系统中
- 进程:进程是程序运行的过程,是一个动态的概念,在进程运行的过程中,系统会有各种指标来表示当前运行的状态,同时进程会随着程序的终止而销毁,不会永久存在系统中
进程与线程
- 假设需要运行360安全卫士程序,会进行资源申请,首先系统申请一块内存空间,然后从硬盘中将代码读取到内存,最后进行其他资源的申请,这个申请资源的过程,我们称为进程(资源单位)
- 当运行该进程中的病毒扫描、漏洞查找、垃圾清理等功能,通常我们会将该功能称为进程中的线程,线程是运行代码的过程,它是一个(执行单位),是进程中的更细的单位,如果该进程有多个线程,线程与线程之间互相不受影响,同时多线程之间可以实现数据共享
- 工厂流水线例子:工厂(操作系统)-->进程(车间)-->线程(流水线作业)
并发与并行
- 并发:多个任务看起来是同时运行,这是一种假并行(
CPU在任务中来回切换)

- 并行:多个任务是真正的同时运行(并行必须有多核
CPU才可以实现)

进程运行的状态
- 一般来说,进程有三个状态,即就绪状态,运行状态,阻塞状态
- 运行状态:进程占用
CPU,并在CPU上运行 - 就绪态:进程已经具备运行条件,但需要等待
CPU的调度才可运行 - 阻塞态:进程因等待某件事发生而暂时不能运行

上述三种状态之间转换分为如下几种情况
- 运行-->阻塞:进程发生
I/O操作,需等待事件,而无法继续执行,则进程由运行状态变为阻塞状态 - 阻塞-->就绪:进程所等待的时间已经完成,但没办法直接运行,需要进入就绪队列,等待调度
- 就绪-->运行:运行的进程时间片已经用完,
CPU会从就绪队列中选择合适的进程分配CPU - 运行-->就绪:
- 1.进程占用
CPU的时间过长,而系统分配给该进程占用CPU的时间是有限的 - 2.当有更高优先级的进程要运行时,该进程需要让出
CPU,由运行状态转变为就绪状态
- 1.进程占用
进程的生命周期
- 生命周期就是指一个对象的生老病死,用处很广

当父进程接收到任务调度时,会通过fork派生子进程来处理,那么子进程会继承父进程属性
1.子进程在处理任务代码时,父进程其实不会进入等待,其运行过程是由linux系统进行调度的
2.子进程在处理任务代码后,会执行退出,然后唤醒父进程来回收子进程的资源
3.如果子进程在处理任务代码过程中异常退出,而父进程却没有回收子进程资源,会导致子进程虽然运行实体已经消失,但仍然在内核的进程表中占据一条记录,长期下去对于系统资源是一个浪费。(僵尸进程)
4.如果子进程在处理任务过程中,父进程退出了,子进程没有退出,那么这些子进程就没有父进程来管理了,由系统的system进程管理。(孤儿进程)
PS:父进程叫PPID,子进程叫PID
进程运行状态监控
- 程序在运行后,我们需要了解进程的运行状态。查看进程的状态分为:
- 静态查看
- 动态查看
静态监控进程ps
ps # report a snapshot of the current processes
-a Select all processes except both session leaders and processes not associated with a terminal.
-u,--userlist(Select by effective user ID (EUID) or name.)以用户为主的进程状态,按用户名和启动时间来显示进程
-x 显示所有程序,不以终端机区分,通常与-a一起使用
-e Select all processes
-f Do full-format listing全格式输出
ps -aux常用组合,查看进程用户、PID、占用cpu百分比、占用内存百分比、状态、执行的命令等
每列指标详解
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
USER:启动进程的用户PID:进程运行的ID号%CPU:进程占用CPU百分比%MEM:进程占用内存百分比VSZ:进程占用虚拟内存大小(单位KB)RSS:进程占用物理内存实际大小(单位KB)TTY:进程是由哪个终端运行启动的,tty1、pts/0等,?表示内核程序与终端无关STAT:进程运行过程中的状态START:进程的启动时间TIME:进程占用CPU的总时间(为0表示还没超过秒)COMMAND:程序的运行指令,[]属于内核态的进程。没有[]属于用户态的进程
查看进程ppid
ppid指的是父进程
ps -ef | grep nginx | grep -v grep
www 26701 115939 0 4月15 ? 00:00:00 nginx: worker process
www 26702 115939 0 4月15 ? 00:00:00 nginx: worker process
www 26703 115939 0 4月15 ? 00:00:00 nginx: worker process
www 26704 115939 0 4月15 ? 00:00:00 nginx: worker process
root 115939 1 0 4月04 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
查看进程树机构
通过pstree可以查看进程树状结构
pstree # display a tree of processes
-p,Show PIDs.:选项指定查看某个进程的树状机构或者看pid
pstree -p 115939
nginx(115939)─┬─nginx(26701)
├─nginx(26702)
├─nginx(26703)
└─nginx(26704)
查看用户进程
1.使用普通用户运行进程
su - xxx -c "sleep 10000" &
[3] 68021
2.使用pgrep过滤用户运行进程名称,以及进程ID
pgrep # look up or signal processes based on name and other attributes
-l List the process name as well as the process ID.
pgrep -l -u xxx
68022 sleep
# -a:表示列出进程pid以及详细命令
pgrep -a -u xxx
68022 sleep 10000
STAT运行状态
stat状态的S、Ss、S+、R、R+等待,都是什么意思?
| STAT基本状态 | 描述 | STAT状态+符号 | 描述 |
|---|---|---|---|
| R | 进程运行 | s | 进程是控制进程,Ss进程的领导者 |
| S | 可中断睡眠 | < | 进程运行在高优先级上,S<优先级较高的进程 |
| T | 进程被暂停 | N | 进程运行在低优先级上,SN优先级较低的进程 |
| D | 不可中断进程 | + | 当前进程运行在前台,R+表示该进程在前台运行 |
| Z | 僵尸进程 | l | 进程是多线程的,Sl表示进程是以线程方式运行 |
进程状态模拟实践
运行进程状态R
1.编写如下脚本
cat > while.sh <<EOF
while true;do((1+1));done
EOF
2.运行该脚本,检查运行状态是否为R
sh # command interpreter (shell)
sh while.sh
ps aux | grep while
root 115971 100 0.0 113280 1208 pts/0 R+ 19:00 2:55 sh while.sh
暂停进程状态T
1.在终端1上运行vim
vim new_file
2.在终端2上运行ps命令查看状态
ps aux | grep new_file
root 116368 0.0 0.0 149560 5084 pts/1 S+ 19:07 0:00 vim new_file
# 在终端1上挂起vim,按下ctrl+z
3.回到终端2再次运行ps命令查看状态
ps aux | grep new_file | grep -v "grep"
root 116368 0.0 0.0 149560 5084 pts/1 T 19:07 0:00 vim new_file
不可中断进程D
1.使用tar打包文件时,可以通过终端不断查看状态,S+,R+,D+
tar -czf etc.tar.gz /etc/ /usr/ /var/
ps aux | grep tar | grep -v grep
实践僵尸进程Z
1.编写python脚本,模拟僵尸进程
cat zombie.py
#!/usr/bin/env python
# encoding: utf-8
from multiprocessing import Process
import time
import os
def task():
print("子进程ID --> %s" % os.getpid())
time.sleep(10)
if __name__ == "__main__":
for i in range(3):
p=Process(target=task)
p.start()
print("父进程ID --> %s" % os.getpid())
time.sleep(100000)
2.运行python脚本
python zombie.py
子进程ID --> 29780
父进程ID --> 29779
子进程ID --> 29781
子进程ID --> 29782
3.通过ps aux查看进程状态
ps aux | grep python
root 29779 0.0 0.0 151296 5808 pts/0 S+ 09:04 0:00 python zombie.py
root 29780 0.0 0.0 0 0 pts/0 Z+ 09:04 0:00 [python] <defunct>
root 29781 0.0 0.0 0 0 pts/0 Z+ 09:04 0:00 [python] <defunct>
root 29782 0.0 0.0 0 0 pts/0 Z+ 09:04 0:00 [python] <defunct>
4.僵尸进程无法杀死,只能通过杀父进程,从而回收僵尸进程
kill # send a signal to a process
# kill僵尸进程没有反应,所以直接kill父进程
kill 29779
实践孤儿进程
1.在窗口1执行如下命令
ping www.baidu.com &> /dev/null &
[1] 52321
2.在窗口2过滤ping进程,杀死其父进程
ps -ef | grep ping | grep -v grep
root 52321 52042 0 16:06 pts/1 00:00:00 ping www.baidu.com
# 强制杀死父进程
kill -9 52042
3.再次查看进程,会发现该进程被系统最高进程pid 1接管
# 孤儿进程被PID为1的父进程接管
ps -ef | grep ping | grep -v grep
root 52321 1 0 16:06 ? 00:00:00 ping www.baidu.com
# 直接kill进程即可关闭
kill 52321
实践多线程Sl
1.使用python脚本编写多线程程序
cat multi_thread.py
#!/usr/bin/env python
from threading import Thread
import time
import os
def task():
time.sleep(200)
if __name__ == "__main__":
print(os.getpid())
for i in range(10):
s=Thread(target=task)
s.start()
2.运行python脚本程序
python multi_thread.py
53162
3.检查python程序状态
# Sl表示多线程
ps aux | grep python | grep -v grep
root 53162 0.0 0.0 871456 5016 pts/0 Sl+ 16:21 0:00 python multi_thread.py
# 通过pstree查看线程
pstree -p 53162
python(53162)─┬─{python}(53163)
├─{python}(53164)
├─{python}(53165)
├─{python}(53166)
├─{python}(53167)
├─{python}(53168)
├─{python}(53169)
├─{python}(53170)
├─{python}(53171)
└─{python}(53172)
高优先级进程S<
1.执行如下命令,让进程在高优先级下运行
nice # run a program with modified scheduling priority
-n,--adjustment
nice -n -20 sleep 200 &
[1] 53626
2.查看进程状态,看是否在高优先级下运行
ps aux | grep sleep | grep -v grep
root 53626 0.0 0.0 108052 360 pts/2 S< 16:29 0:00 sleep 200
低优先级进程SN
1.执行如下命令,让进程在低优先级下运行
nice -n 20 sleep 200 &
[1] 53816
2.查看进程状态,看是否在低优先级下运行
ps aux | grep sleep | grep -v grep
root 53816 0.0 0.0 108052 356 pts/0 SN 16:33 0:00 sleep 200
动态监控进程top
- 使用
top命令查看当前的进程状态(动态)
top # display Linux tasks
top命令选项
- 执行
top命令时可以指定的命令选项-d:Delay time interval(默认3秒刷新一次)-p:Monitor PIDs-u:Monitor by user
- 示例用法:
# 仅查看指定进程动态享请 top -d 1 -p pid top -d 1 -p $(pgrep nginx) # 动态查看普通用户运行的进程 top -d 1 -u xxx
top内部选项
- 执行
top后可使用的选项P:按CPU进行排序M:按内存进行排序R:对排序后的结果进行倒序f:自定义显示的字段,比如打印PPID,按空格选好后,按q退出k:指定杀死某个id1:显示cpu核心数z:以高亮显示数据b:高亮显示处于R状态的进程
top字段含义
w # Show who is logged on and what they are doing
uptime # Tell how long the system has been running
top - 21:21:10 up 34 days, 3:12, 1 user, load average: 0.01, 0.02, 0.05
Tasks: 139 total, 1 running, 138 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 8154640 total, 5741288 free, 670300 used, 1743052 buff/cache
KiB Swap: 4194300 total, 4194300 free, 0 used. 7082944 avail Mem
top字段含义load average: 0.01, 0.02, 0.05:1分钟、5分钟、15分钟平均负载Tasks:139 total:当前进程的总数1 running:正在运行的进程数138 sleeping:睡眠的进程数0 stopped:停止的进程数0 zombie:僵尸进程数
%Cpu(s)含义0.0 us:系统用户进程使用CPU百分比0.0 sy:内核中的进程占用CPU百分比,通常内核是与硬件进行交互0.0 ni:高优先级进程占用CPU百分比100.0 id:空闲CPU的百分比0.0 wa:CPU等待IO完成的时间0.0 hi:硬中断,占的CPU百分比0.0 si:软中断,占的CPU百分比0.0 st:比如虚拟机占用物理CPU的时间
如何理解中断
- 中断是系统用来响应硬件设备请求的一种机制,它会打断进程的正常调度和执行,然后调用内核中的中断处理程序来响应设备的请求
- 中断其实是一种异步的事件处理机制,可以提高系统的并发处理能力
- 网卡接收到数据包后,会通过硬件中断的方式,通知内核有新的数据到了。这时,内核就应该调用中断处理程序来响应网卡
- 对上半部来说,既然是快速处理,其实就是要把网卡的数据读到内存中,然后更新一下硬件寄存器的状态(表示数据已经读好了),最后再发送一个软中断信号,通知下半部做进一步的处理
- 而下半部被软中断信号唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它送给应用程序
- 上半部直接处理硬件请求,也就是我们常说的硬中断,特点是快速执行(在中断禁止模式下运行)
- 下半部则是由内核触发,也就是我们常说的软中断,特点是延迟执行
内存相关命令
free # Display amount of free and used memory in the system
-m Display the amount of memory in megabytes. -w:buffer/cache分开列
- 一般查看内存使用
free命令,需要了解每列含义,以及计算公式:total总内存计算公式:used + free + buffer + cache = totalused已使用内存计算公式:total - free - buffer - cache = usedfree未被使用的内存计算公式:total - used - buffer -cache = freeavailable可获得内存计算公式:free + (buffer+cache可释放的空间) = available
free -m
total used free shared buff/cache available
Mem: 7963 650 5610 93 1702 6921
Swap: 4095 0 4095
- 需要注意:
free:表示的当前没有被程序使用的内存buffer/cache:在有需要时,是可以被释放出来以供其他进程使用的available:表示系统目前能提供给新应用程序使用的内存
- 收单释放内存
buffer/cache- 第一步:
syn - 第二步:
echo "3" > /proc/sys/vm/drop_caches
- 第一步:
管理进程状态
当程序运行为进程,如果需要关闭进程,则需要使用kill、killall、pkill等命令对进程ID发起关闭信号
系统支持的信号
kill # send a signal to a process
- 使用
kill -l列出当前系统所支持的信号,虽然支持的信号很多,但我们仅以最常用的3个信号为例1(SIGHUP):通常用来重新加载配置文件9(SIGKILL):强制杀死进程15(SIGTERM):终止进程,默认kill信号
关闭进程kill
1.安装vsftpd服务,然后启动
yum install vsftpd
systemctl start vsftpd
2.修改vsftpd的配置文件,然后发送重载信号
# 改变路径
echo "anon_root=/opt" >> /etc/vsftpd/vsftpd.conf
# 重载服务
kill -1 81379
3.发送停止进程信号
kill -15 9160
4.发送强制停止信号,当无法停止服务时,可强制终止信号
kill -9 9160
关闭进程pkill
pkill # look up or signal processes based on name and other attributes
killall # kill processes by name
1.通过pkill、killall指定进程服务名称,然后将其进程关闭
pkill nginx
killall nginx
2.使用pkill将远程连接用户踢下线
pkill -9 -t pts/0
进程优先级
什么是进程优先级
- 优先级指的是优先享受资源,比如排队买票时,军人优先、老人优先
- 系统优先级:优先使用
cpu资源
为何需要优先级
- 举个例子:海底捞火锅正常情况下响应就特别慢,那么当节假日时人员突增会导致处理请求特别慢
- 那假设我是海底捞
VIP客户(最高优先级),无论多么繁忙,我都无需排队,海底捞人员直接服务于我,满足我的需求 - 如果我不是
VIP的人员(较低优先级)则进入排队等待状态
- 那假设我是海底捞
进程如何配置优先级
- 在启动进程时,为不同的进程使用不同的调度策略
nice值越高:表示优先级越低,例如+19,该进程容易将CPU使用量让给其他进程nice值越低:表示优先级越高,例如-20,该进程不倾向于让出CPU
进程优先级如何查看
1.使用top命令查看优先级
# NI:显示nice值,默认是0
# PR:显示nice值,-20映射到0,+19映射到39
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 191144 4192 2628 S 0.0 0.1 3:29.21 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.52 kthreadd
2.使用ps o, Specify user-defined format.命令查看进程优先级
vim
ps axo command,nice | grep vim | grep -v grep
vim 0
指定进程启动优先级nice
nice # run a program with modified scheduling priority
-n,--adjustment
1.启动vim并且指定程序优先级为 -5
nice -n -5 vim &
[1] 128875
2.查看当前vim进程的优先级
ps axo pid,command,nice | grep 128875 | grep -v grep
128875 vim -5
修改进程优先级renice
1.查看当前正在运行的sshd进程优先级状态
ps axo pid,command,nice | grep [s]shd
936 /usr/sbin/sshd -D 0
128242 sshd: root@pts/0,pts/1 0
2.调整sshd主进程的优先级
renice # alter priority of running processes
renice -n -20 936
936 (进程 ID) 旧优先级为 0,新优先级为 -20
3.调整之后如下,需要退出终端,重新打开一个终端,子进程才会继承主进程的优先级
ps axo pid,command,nice | grep [s]shd
936 /usr/sbin/sshd -D -20
128242 sshd: root@pts/1,pts/0 0
exit # cause the shell to exit
4.再次登录sshd服务,会由主进程fork子sshd进程(那么子进程会继承主进程的优先级)
ps axo pid,command,nice | grep [s]shd
936 /usr/sbin/sshd -D -20
130382 sshd: root@pts/0 -20
后台进程管理
什么是后台进程
通常进程都会在终端前台运行,一旦关闭终端,进程也会随着结束
那么此时我们就希望进程能在后台运行,就是将在前台运行的进程放入后台运行,这样即使我们关闭了终端也不影响进程的正常运行
为什么需要后台运行
比如:我们在向别的服务器传输大文件时,由于网络的问题需要传输很久,如果在传输的过程中出现网络抖动或者不小心关闭了终端会导致传输失败,如果能将传输的进程放入后台,是不是就能解决此类问题了
如何将进程转为后台
早期的时候大家都选择使用nohup + &符合将进程放入后台,然后再使用jobs、bg、fg等方式查看进程状态,但太麻烦了也不直观,所以我们推荐使用screen
nohup方式
nohup # run a command immune to hangups, with output to a non-tty
1.使用nohup将前台进程转到后台运行
nohup sleep 3000 &
[1] 4175
2.查看进程运行情况
ps axu | grep [s]leep
root 4175 0.0 0.0 108052 360 pts/0 S 17:53 0:00 sleep 3000
3.使用jobs、bg、fg等方式查看后台作业
# 查看后台作业
jobs
[1]+ 运行中 nohup sleep 3000 &
fg %1 # 转为前台运行(run jobs in the foreground)
bg %1 # 转为后台运行(run jobs in the background)
screen方式
screen manager with VT100/ANSI terminal emulation
1.安装screen工具
yum install screen
2.开启一个screen子窗口,可以通过-S sessionname为其指定名称
screen -S test
3.在screen窗口中执行任务,可以执行前台运行的任务
4.使用ctrl+a+d平滑退出screen,但不会终止screen中的前台任务。
[detached from 4890.test]
5.查看当前有多少screen正在运行
screen -list
There is a screen on:
4890.test (Detached)
1 Socket in /var/run/screen/S-root.
6.可以通过screenid或screen标签名称进入
screen -r 4890
screen -r test
exit # 退出进程,结束screen
[screen is terminating]
系统平均负载
- 每次发现系统变慢时,通常做的第一件事,就是执行
top或uptime来了解系统的负载情况 - 比如像下面这样,在命令行里输入了
uptime命令,系统也随即给出了结果
uptime # Tell how long the system has been runninguptime 19:33:51 up 35 days, 1:25, 1 user, load average: 0.00, 0.01, 0.05 # 前面几列,分别是当前时间、系统运行时间以及正在登录用户数 # 而最后三个数字呢,依次分别是过去1分钟、5分钟、15分钟的平均负载(load blance)
什么是平均负载
- 平均负载是单位时间内
CPU使用率吗;- 上面的0.05代表
CPU使用率是5%?其实不是
- 上面的0.05代表
- 那如何理解平均负载:
- 平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数;或者理解平均负载是单位时间内的活跃进程数
- 平均负载与
CPU使用率并没有直接关系
可运行状态
- 可运行状态进程
- 指正在使用
CPU或者正在等待CPU的进程,也就是我们ps命令看到处于R + S状态的进程
不可中断状态
- 不可中断进程
- 系统中最常见的是等待硬件设备的
I/O响应,通过ps命令中看到D(Disk Sleep)的进程 - 例如:当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程中断打断的,这个时候的进程就处于不可中断状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题
- 所以,不可中断状态实际是系统对进程和硬件设备的一种保护机制
平均负载为多少时合理
- 理想的状态是每个
CPU上都刚好运行着一个进程,这样每个CPU都得到了充分利用 - 所以在评判平均负载时,首先你要知道系统有几个
CPU通过top命令获取,或/proc/cpuinfo,或lscpu # display information on CPU architecture - 示例:假设现在在4、2、1核的
CPU上,如果平均负载为2时,意味着什么- 1.在4个
CPU的系统上,意味着CPU有50%的空闲 - 2.在2个
CPU的系统上,意味着所有的CPU都刚好被完全占用 - 3.而1个
CPU的系统上,则意味着有一半的进程竞争不到CPU
- 1.在4个
- 平均负载有三个数值,我们应该关注哪个呢?
- 实际上,平均负载中的三个指标我们其实都需要关注。(就好比一天的天气要结合起来看)
- 1分钟、5分钟、15分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳
- 1分钟的值小于15分钟的值,说明系统最近1分钟的负载在减少,而过去15分钟内却有很大的负载
- 如果1分钟的值远大于15分钟的值,就说明最近1分钟的负载在增加,这种增加有可能只是临时性的,也有可能还会持续上升,所以就需要持续观察
- 一旦一分钟的平均负载接近或超过了
CPU的个数,就意味着系统正在发生过载的问题,这时就得分析问题,并要想办法优化了 - 例:假设我们在有2个
CPU的系统上看到平均负载为2.73,6.90,12.98- 那么说明在过去1分钟内,系统有136%的超载(2.72/2=136%)
- 而在过去5分钟内,有345%的超载(6.90/2=345%)
- 而在过去15分钟内,有649%的超载(12.98/2=649%)
- 但从整体趋势来看,系统的负载是在逐步的降低
平均负载与CPU使用率
- 在实际工作中,我们经常容易把平均负载和
CPU使用率混淆,所以在这里,也要做一个区分 - 既然平均负载代表的是活跃进程数,那平均负载高了,不就意味着
CPU使用率高吗? - 我们回到平均负载的含义上来,平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数
- 所以,它不仅包括了正在使用
CPU的进程,还包括了等待CPU和等待I/O的进程 - 而
CPU使用率,是单位时间内CPU繁忙情况的统计,跟平均负载并不一定完全对应。比如:CPU密集型进程,使用大量CPU计算会导致平均负载升高,此时这两者是一致的I/O密集型进程,等待I/O也会导致平均负载升高,但CPU使用率不一定很高- 大量的
CPU进程调度也会导致平均负载升高,此时的CPU使用率也会比较高
留言