Linux 进程管理
Program
是一个静态实体,只是存储在操作系统中的文件(集合)
Process
是操作系统上的活动(Active)实体,是 Program
由操作系统加载到内存并运行之后的实体。
Process
运行过程中需要操作系统为其分配各种资源,如 CPU、Memory、Files、IO 等来完成其运行。
如果一个 Program
被操作系统运行(启动)了多次,那么其产生的多个 Process
属于分割(单独)的实体。
Linux 系统中调度的进程/线程,通常被称为任务(Task)
Linux 中常见的进程状态如下表:
状态标识 | 状态名称 | 状态说明 | 示例 |
---|---|---|---|
R |
task_running | 进程处于运行或就绪状态 | |
S |
task_interruptible sleeping |
可中断的睡眠状态 | |
D |
task_uninterruptible | 不可中断的睡眠状态 1. 它是一种睡眠状态,意味着处于此状态的进程不会消耗 CPU 2. 睡眠的原因是等待某些资源(比如锁或者磁盘 IO),这也是非常多 D 状态的进程都处在处理 IO 操作的原因 3. 是它不能被中断,这个要区别于 硬件中断 的中断,是指不希望在其获取到资源或者超时前被终止。因此他不会被信号唤醒,也就不会响应 kill -9 这类信号。这也是它跟 S(可中断睡眠) 状态的区别 |
|
T |
task_stopped task_traced Traced |
暂停状态或跟踪状态 | |
Z |
task_dead exit_zombie zombie |
退出状态,进程成为僵尸进程 | |
X |
task_dead exit_dead |
退出状态,进程即将被销毁 | |
I |
idle | 空闲状态 | |
+ |
表示关联了前台操作(Foreground Operation),比如前台运行的进程 |
进程调度
Linux 中任务(Task)调度算法默认使用 CFS(Completely Fair Scheduler,内核版本 >= 2.6.23).
CFS 调度算法没有使用固定的进程(此处的进程可能是进程或者线程,Linux 中统称为 Task)优先级(Priority),而是根据进程的 nice value
为进程分配一定比例的(Proportional) CPU 计算时间。 [1]
nice
的取值从 -20
- +19
,值越小,优先级越高,默认值为 0
。优先级高的进程会被分配到更高比例的 CPU 处理时间。
在 Linux 内核中,优先级分为两种:静态优先级和动态优先级。CFS 使用的是动态优先级,它是根据 nice
值计算出来的。
CFS Scheduler 不会直接设定 Priorities,而是为每个 Task 维护变量 vruntime(virtual runtime)
(可以检查系统 /proc/<PID>/sched
),这个值记录了每个 task 使用了多少 CPU 时间。
CFS 通过将进程的虚拟运行时间(vruntime
)与其他进程的虚拟运行时间进行比较来决定调度优先级。权重越大,vruntime
增长越慢,意味着进程的优先级越高,能够更频繁地被调度。
假入一个任务有默认的 Priority(nice=0
),那么他的 vruntime
和实际使用的 CPU 时间相同。例如一个 nice=0
的进程使用了 CPU 200ms,那么他的 vruntime=200ms
。低优先级(low priority,nice>0
) 的任务在 CPU 上运行了 200ms,那么他的 vruntime>200ms
,相反的,一个 高优先级(high priority,nice<0
) 的任务在 CPU 上运行了 200ms,那么他的 vruntime<200ms
。基于此,CFS Scheduler 在选择下一个要执行的任务时,会选择 vruntime
最小的任务来运行。如果有高优先级的任务就绪(可执行),它会抢占(preemptive)正在执行的低优先级的任务。
假如 Linux 中有 2 个优先级一样的任务(nice=0
),一个进程为 I/O-bound,另一个为 CPU-bound。通常情况下,在一个 CPU 周期内,I/O-bound 的任务会使用很少的 CPU 时间就会因等待 IO 而中断在 CPU 上的执行并进入 CPU 的等待调度队列(schedule queue),而 CPU-bound 的任务会用尽分配给它的整个 CPU 周期。执行一段时间之后, I/O-bound 的任务的 vruntime
的值会显著的小于 CPU-bound 的任务的 vruntime
,导致 I/O-bound 的任务拥有比 CPU-bound 的任务更高的优先级,当 I/O-bound 的任务就绪(IO 返回数据)时,它会立即抢占 CPU 开始执行。
nice
只能针对单一的进程调整优先级,无法同时将优先级配置关联到相关进程,如 子进程或者同一个服务中的其他进程
修改 nice 的值
在 Linux 中,nice
值用于调整进程的优先级,数值范围从 -20
( 最高优先级 )到 19
( 最低优先级 )。较低的 nice
值表示进程有更高的优先级,会更频繁地获得 CPU 时间,而较高的 nice
值表示进程有较低的优先级。
你可以使用 nice
和 renice
命令来修改进程的 nice
值
普通用户(
root
之外的用户)启动应用程序时默认只能配置初始nice
值0-19
普通用户(
root
之外的用户)修改正在运行的应用程序的nice
值,只能改大,不能改小。比如进程启动时,其nice
为10
,拥有权限的普通用户只能将其nice
值改为大于10
的值。
nice 命令
nice
命令用于在启动进程时指定 nice
值 。如果不指定,默认 nice
值为 0
。
nice -n 10 command |
renice 命令
renice
命令可以修改已经在运行的进程的 nice
值。需要提供进程 ID( PID )来指定要修改的进程。
renice <nice_value> -p <PID> |
如果想要一次修改多个进程的 nice
值,可以传递多个 PID:
sudo renice 10 -p 1234 2345 3456 |
Linux 进程资源控制 cgroups
cgroups
可以将一个任务(task
)标识(绑定)到一个特殊的 控制组(Control Group
) ,此任务启动的子进程可以继承父进程的 控制组(Control Group
)
控制组(Control Group
) 可以限制的资源类型如下:
Type | Description |
---|---|
blkio |
Storage 限制到存储设备(如 Hard Disk、USB Drivers等)的请求 |
cpu |
CPU 限制 CPU 调度 |
cpuacct |
Process Accounting 上报 CPU 使用状态,可以用于统计客户端使用的处理量并进行收费 |
cpuset |
CPU Assignment 在多处理器的系统上,将 Task 分配到特定的处理器以及关联的内存 |
devices |
Device Access 限制 控制组( Control Group ) 中的 Task 对目标设备类型的使用 |
freezer |
Suspend/Resume 暂停/恢复 控制组( Control Group ) 中的 Task |
memory |
Memory Usage 限制并报告 控制组( Control Group ) 中的 Task 使用的内存 |
net_cls |
Network Bandwidth 制并报告 控制组( Control Group ) 中的 Task 使用的网络流量,主要通过对网络流量打上 cgroups 相关标签实现 |
net_prio |
Network Traffic 控制 控制组( Control Group ) 中的网络流量的优先级 |
ns |
Namespaces 将 cgroups 分配到不同的 Namespaces,如此同一个 cgroups 中的进程只能看到本 Namespace 中的进程 |
Linux 进程管理
top 命令
使用 top
命令可以查看系统负载、CPU 和 内存使用情况。也可以查看单个进程的具体信息。
top
命令常用选项
选项 | 说明 | 示例 |
---|---|---|
-H |
Threads Mode ,线程模式。默认情况 top 展示进程的简要信息,使用此选项显示进程中的线程状态。对应交互式命令 H |
- 显示单个进程的(线程)详细信息
top -H -p 1423
top - 09:44:42 up 54 days, 23:53, 2 users, load average: 8.82, 6.84, 7.21
Threads: 15 total, 0 running, 15 sleeping, 0 stopped, 0 zombie
Cpu(s): 40.9 us, 10.8 sy, 0.0 ni, 48.1 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 15790488 total, 466056 free, 7761544 used, 7562888 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 3895716 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1423 root 20 0 1477368 778788 4260 S 39.5 4.9 11999:41 [watchdog:1:6]
2572 root 20 0 1477368 778788 4260 S 37.9 4.9 11363:48 [watchdog:1:6]
1436 root 20 0 1477368 778788 4260 S 34.2 4.9 11286:08 [watchdog:1:6]
1435 root 20 0 1477368 778788 4260 S 33.9 4.9 12059:53 [watchdog:1:6]
1434 root 20 0 1477368 778788 4260 S 33.2 4.9 10249:00 [watchdog:1:6]
1437 root 20 0 1477368 778788 4260 S 30.6 4.9 11717:47 [watchdog:1:6]
1431 root 20 0 1477368 778788 4260 S 28.9 4.9 11222:06 [watchdog:1:6]
21378 root 20 0 1477368 778788 4260 S 27.6 4.9 12143:35 [watchdog:1:6]
1433 root 20 0 1477368 778788 4260 S 17.6 4.9 8738:21 [watchdog:1:6]
1428 root 20 0 1477368 778788 4260 S 8.0 4.9 7650:56 [watchdog:1:6]
1429 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.04 [watchdog:1:6]
1430 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.05 [watchdog:1:6]
1432 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.03 [watchdog:1:6]
1438 root 20 0 1477368 778788 4260 S 0.0 4.9 12260:30 [watchdog:1:6]
1529 root 20 0 1477368 778788 4260 S 0.0 4.9 11068:39 [watchdog:1:6]
进程命令名和进程可执行文件名
在系统中遇到以下进程:
ps -elf | grep 18686 |
其中 PID 为 18686
的进程名为 /usr/sbin/CROND
,其启动了另外两个子进程。但是在系统中检查,并不存在路径 /usr/sbin/CROND
ls -l /usr/sbin/CROND |
出现此种现象,主要是因为 在启动时,进程的命令名是根据路径传递给 execve()
函数的参数决定的,而不是直接与系统中的文件进行匹配。
在 Linux 系统中,ps
命令显示的进程信息是从 /proc
文件系统中获取的,而 /proc
文件系统包含有关正在运行的进程的信息,包括每个进程的命令名。因此,即使实际上系统中不存在 /usr/sbin/CROND
文件,但如果进程的命令名是 /usr/sbin/CROND
,那么 ps
命令仍然会显示进程的命令名为 /usr/sbin/CROND
。
进程的命令名可以查看 /proc/<PID>/cmdline
文件,本示例中显示如下:
cat /proc/18686/cmdline |
对应的系统上的可执行文件的名称可以查看 /proc/<PID>/stat
、/proc/<PID>/comm
、/proc/<PID>/status
等文件
cat /proc/900/comm |
在本示例中,实际执行的命令为 crond
参考链接|Bibliography
Operating System Concepts v10 Online
Linux进程状态说明
脚注
- 1.Operating System Concepts v10 Online 5.7.1 Example: Linux Scheduling ↩