进程管理

进程 - 正在运行的程序

PID     进程唯一标识符 (是16位正整数 0-65535)(2^15 = 65535 无符号的短整型 short int)
PPID    父进程的PID

软件 -> 至少有一个程序 -> 至少有一个进程 -> 至少有一个线程

ELF可执行文件主要分段(PPP1):
    readelf -h /bin/cp  查看可执行文件的elf头
    readelf -l /bin/cp  查看可执行文件的elf头详细信息

    BSS         存储未初始化全局变量
    DATA        存储初始化的全局变量
    RODATA      存储常量
    TEXT        存储指令集

程序运行的过程:
    建立虚拟空间(分配一个页目录)->
    建立虚拟空间与可执行文件映射(页目录项指向磁盘的程序) ->
    跳到程序入口 -> 缺页异常-> 在内存中寻找空闲页,将对应的页换入 ->
    建立映射 -> 开始执行。


进程独立虚拟内存空间, 实现进程间隔离

进程之间通讯(内核提供) IPC
    信号            异常通知
    管道            数据通信(基于I/O)
    套接字          数据通信(多应用于网络 协议)
    消息队列        数据通信(队列)
    共享内存        数据通信(将虚拟地址映射同一块物理地址)
    信号量(信号灯)  并发处理

进程和线程
    进程独立内存空间, 会产生进程间通讯
    线程独立栈空间, 依赖进程空间

进程列表命令

top 文本任务管理器

    ?       帮助
    q       退出
    k(小写)       结束进程 然后输入对应的进程pid号就可以结束对应的进程了。
    空格    实时刷新
    
    S  时间on 或off
    z, y 切换高亮显示,z排序字段默认CPU y运行任务。
    z,b。 切换:“ z”颜色/单色; 'b'粗体/反向(仅当'x'或'y'时)
    d或者s 设置实时更新时间间隔,默认3秒。
    W 写入配置文件。就是保存当前的设置。
    Y  检查其他输出。

    截取两帧数据到top.txt文件中(PPP2)
        top -d 0.5 -b -n 2 > /tmp/top.txt

image-20200701004401954.png

  • 第一行:系统运行时间和平均负载

当前时间、系统已运行时间、当前登录用户的数量、最近5、10、15分钟内的平均负载

  • 第二行:任务

任务的总数、运行中(running)的任务、休眠(sleeping)中的任务、停止(stopped)的任务、僵尸状态(zombie)的任务

  • 第三行:cpu状态
字段字段释义
ususer: 运行(未调整优先级的) 用户进程的CPU时间
sysystem: 运行内核进程的CPU时间
niniced:运行已调整优先级的用户进程的CPU时间
ididle:空闲时间
waIO wait: 用于等待IO完成的CPU时间
hi处理硬件中断的CPU时间
si处理软件中断的CPU时间
st这个虚拟机被hypervisor偷去的CPU时间(译注:如果当前处于一个hypervisor下的vm,实际上hypervisor也是要消耗一部分CPU处理时间的)
  • 第四行:内存

全部可用内存(total)、空闲内存(free)、已使用内存(used) 、缓冲内存(buff/cache)

  • 第五行:swap

全部、已使用、空闲和缓冲交换空间

  • 第七行至N行:各进程任务的的状态监控
字段释义
PID进程ID,进程的唯一标识符
USER进程所有者的实际用户名
PR进程的调度优先级。这个字段的一些值是'rt'。这意味这这些进程运行在实时态。
NI进程的nice值(优先级)。越小的值意味着越高的优先级。负值表示高优先级,正值表示低优先级
VIRTvirtual memory usage 虚拟内存,进程使用的虚拟内存。进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES1、进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据等 2、假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而不是实际的使用量
RESresident memory usage 常驻内存,驻留内存大小。驻留内存是任务使用的非交换物理内存大小。进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA1、进程当前使用的内存大小,但不包括swap out 2、包含其他进程的共享 3、如果申请100m的内存,实际使用10m,它只增长10m,与VIRT相反 4、关于库占用内存的情况,它只统计加载的库文件所占内存大小
SHRSHR:shared memory 共享内存1、除了自身进程的共享内存,也包括其他进程的共享内存 2、虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小 3、计算某个进程所占的物理内存大小公式:RES – SHR 4、swap out后,它将会降下来
S这个是进程的状态。它有以下不同的值:D - 不可中断的睡眠态。R – 运行态S – 睡眠态T – 被跟踪或已停止Z – 僵尸态
%CPU自从上一次更新时到现在任务所使用的CPU时间百分比。%CPU显示的是进程占用一个核的百分比,而不是整个cpu(N核)的百分比,有时候可能大于100,那是因为该进程启用了多线程占用了多个核心,所以有时候我们看该值得时候会超过100%,但不会超过总核数*100
%MEM进程使用的可用物理内存百分比
TIME+任务启动后到现在所使用的全部CPU时间,精确到百分之一秒
COMMAND运行进程所使用的命令。进程名称(命令名/命令行)

交互命令

Z:改变颜色;

1) S 设置摘要数据颜色(就是最上面的信息颜色)。 M 设置消息提示的颜色 H 设置头部一行的颜色 T 设置主体的颜色

     “ a”或“ w”来提交和更改另一个,切换颜色搭配的模板。

B:加粗 E/e 设置界面 B设置头部信息粗体显示(默认粗体) E/e(设置后缀信息m/g/t/p)默认是不带任何后缀。

t:显示和隐藏任务/cpu信息;m:内存信息

1:监控每个逻辑CPU的状况;

f/F f” /“ F”添加/删除/排序/排序

    进入排序界面,前面有*表示会在界面显示的信息,按d或者空格可以切换显示信息或不显示。
    按->左键可以选中然后可以修改显示的顺序,然后敲回车就可以了。s是设置排序,默认是按照cpu排序的。

R:正常排序/反向排序;

s:设置刷新的时间--------常用

i:忽略闲置和僵死进程。这是一个开关式命令。

r:重新安排一个进程的优先级别。系统提示用户输入需要改变的进程PID以及需要设置的进程优先级值。输入一个正值将使优先级降低,反之则可以使该进程拥有更高的优先权。默认值是10。

c:切换显示命令名称和完整命令行。

M:根据驻留内存大小进行排序。-------------常用

P:根据CPU使用百分比大小进行排序。-----------常用

H:显示线程

l,t,m: 切换摘要:'l'加载平均值; “ t”任务/ CPU统计信息; 'm'内存信息,切换信息显示方式

L : 查找相关应用信息。搜索

u/U:输入用户,显示用户的任务 如: nginx 会查出nginx相关进程。

ps 列表进程(PPP3)

    ps          列出当前终端运行的程序
    ps -aux     列出所有进程信息(BSD)
    ps -ef      列出所有进程信息
    ps -e -o pid,comm,ppid       自定义显示字段
    ...

    ps -aux和ps -ef的区别
        1. -ef是System V展示风格,而aux是BSD风格。

            ps -aux
            USER  PID %CPU %MEM    VSZ   RSS  TTY   STAT START TIME  COMMAND
            root    1  0.0  0.1 193832  6904  ?     Ss   9月28 0:12  /usr/lib/systemd/systemd --switched-root --system--deserialize 22

            字段含义:
            USER:    用户名称
            PID:     进程号
            %CPU:    进程占用CPU的百分比
            %MEM:    进程占用物理内存的百分比
            VSZ:     进程占用的虚拟内存大小(单位:KB)
            RSS:     进程占用的物理内存大小(单位:KB)
            TTY:     终端名称(缩写),若为?,则代表此进程与终端无关,因为它们是由系统启动的
            STAT:    进程状态
            START:   进程的启动时间
            TIME:    CPU时间,即进程使用CPU的总时间
            COMMAND: 启动进程所用的命令和参数,如果过长会被截断显示

            ps -ef
            UID   PID  PPID  C STIME TTY      TIME   CMD
            root    1     0  0 9月28 ?    00:00:12   /usr/lib/systemd/systemd --switched-root --system --deserialize 22

            字段含义:
            UID:   用户ID
            PID:   进程ID
            PPID:  父进程ID
            C:     CPU用于计算执行优先级的因子。数值越大,表明进程是CPU密集型运算,执行优先级会降低;数值越小,表明进程是I/O密集型运算,执行优先级会提高
            STIME: 进程启动的时间
            TTY:   完整的终端名称
            TIME:  CPU时间
            CMD:   完整的启动进程所用的命令和参数

            2. COMMADN列如果过长,aux会截断显示,而ef不会

            总结:
                如果想查看进程的CPU占用率和内存占用率,可以使用aux
                如果想查看进程的父进程ID和完整的COMMAND命令,可以使用ef

pstree 打印进程树

    pstree -p   带PID的进程树

pgrep   按进程名查找进程
    pgrep vim
    pgrep -u root

进程控制(信号机制的发信号)

信号源

    kill -l  
    列出全部信号名称
    
说明:

只有第9种信号(SIGKILL)才可以无条件终止进程,其他信号进程都有权利忽略。 下面是常用的信号:

HUP    1    终端断线

INT     2    中断(同 Ctrl + C)

QUIT    3    退出(同 Ctrl + \)

TERM   15    终止

KILL    9    强制终止

CONT   18    继续(与STOP相反, fg/bg命令)

STOP    19    暂停(同 Ctrl + Z)

终止操作

    kill -15 PID

杀死进程

    kill -9 PID

终止和杀死的区别
    当进程在进行一个关键性操作的时候, 15不能立即杀死他, 需要这个进程先处理玩自己的事情才能杀掉
    而这个时候还是想杀死这个进程的话, 就可以使用9号信号, 9号信号是必杀信号

捕捉信号
    trap 操作 信号源

    9和19不能捕捉

通过进程名杀死进程
    杀死进程名带有关键词的进程
        pkill -9 关键词

    杀死对应进程名的进程
        pkill -9 -x 进程名

    杀死对应root用户的所有进程
        pkill -u root
        
  Linux Shell脚本实现根据进程名杀死进程
  ps -ef |grep check-domain.sh |grep -v grep |awk '{print $2}' | xargs kill -9

进程状态

在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程再创建新的进程。

子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。
当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

R       运行状态
S       睡眠状态
D       不可中断睡眠状态
Z       僵尸进程

孤儿进程

    一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程

    一个进程使用fork创建子进程,如果子进程退出工作状态,而父进程并没有调用wait()或waitpid()获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。

进程的正常结束: 子进程要给父进程返回进程状态

问题及危害:
    linux提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息,就可以得到。

    这种机制就是:
        在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。
        但是仍然为其保留一定的信息(PID,  运行时间, 退出状态等),
        直到父进程通过wait / waitpid来取时才释放。

    这样就导致了问题:
    如果父进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,
        但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程.
    此即为僵尸进程的危害,应当避免。

    孤儿进程是没有父进程的进程,收集孤儿进程的退出信息的这个重任就落到了init进程身上,
    init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,
        内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。
    这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会出面处理它的一切善后工作。
    因此孤儿进程并不会有什么危害。

任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。
这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,
    这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。
如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。


    杀死僵尸进程, 只需要将僵尸进程父进程干掉就可以了,
    僵尸进程这个时候就被init(1号进程)接管, 成为这个子进程的父进程,这个僵尸进程就变成了孤儿进程。

    查看是否有僵尸进程的简略方法:
        ps -aux | grep Z
        ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'

进程优先级(NI)

进程优先级范围: -20 到 19, 数值越小, 优先级越高
普通用户只能将进程优先级数值调大, 不能调小

查看进程优先级: ps -el / top / ps -eo pid,ni,comm

nice        指定运行程序的进程优先级(PPP5)
    nince -n 19 tar -xf mysql.tar.bz2

renice      更改正在运行程序的进程优先级(PPP6)
    sudo renice -19 PID

占用cpu一个核心: nice -n 0 cat /dev/urandom > /dev/null

查看进程优先级设置的变化: time nice -n -20 head -c 1m /dev/urandom > /dev/null

进程组

进程组包含一个或多个进程, 用于进程分组, 方便管理进程
每个进程都会所属一个进程组, 默认与父进程同属一个组

进程组也有唯一标识符(pgrp), 进程组组长PID即是进程组ID
创建进程组的人即是进程组组长, 进程组组长不能再创建进程组

由于进程组ID与进程组组长的PID一致,操作组长进程直接操作PID即可, 操作进程组在PID前面加负(-)号

    给进程组长发信号:   kill -9  1023
    给进程组发信号:     kill -9 -1023
    给本进程组发信号:   kill -9  0
    给所有进程发信号:   kill -9 -1

会话

一个会话包含一个进程组或多个进程组
一个会话对应一个控制终端(输入输出)
一个会话包含进程组分为前台进程组和后台进程组
使用控制终端的进程组即是前台进程组, 其它全为后台进程组
会话与进程组一样,都唯一标识符, 也有管理者(会长)
进程组组长不能创建会话

作业管理(PPP8)

    一个程序正在运行的时候, 可以把这个程序放到后台去运行,不占前台的资源
    ps          查看当前会话所有进程组

    jobs        查看当前会话的所有后台进程组(任务)
        jobs -l     列出后台进程组带PID显示
        jobs -s        只列出暂停的jobs
        jobs -r        只列出运行的jobs

    ctrl + z    将前台进程组切换到后台停止, 在终端运行无效果
    ctrl + c    再终端运行的话会把当前终端运行的任务停止
    ctrl + d    在终端运行的时候会关闭当前终端

    gedit &     将gedit进程切换到后台

    fg          将后台进程组切换到前台运行(默认将最后的后台进程组调到前台)
        fg 2    将ID为2的后台进程组调到前台运行

    bg          将后台进程组停止状态改为运行状态
        bg 2    将jobs列表ID对应2的后台进程组停止状态改为运行状态

    vncview &                   在后台运行vnc,不会占前台终端的资源

后台复制大文件
    生成指定大小的文件
        head -c 500M /dev/zero > swapfile

        dd if=/dev/zero of=./swapfile bs=100M count=5

     cp /soft/* /test/ -rf
        如果你要做一个大文件的拷贝,不加后台符号这个终端就只能等它拷完才能用

    但这里还考虑一个问题,如果它还没有拷完,而我不小心把这个终端关了,
    那么这个程序也会停止,造成没拷完的情况
    所以把要做的事锁定到后台,在前面加一个nohup命令就可以了,
    在后面加一个&号也是可以的

nohup 命令

nohup cp /soft/* /test/ -rf &
把复制的终端关闭,再开一个终端查看,用jobs -l也是看不到这个job
(因为换了终端),但是拷贝仍在继续)
cp /soft/* /test/ -rf &
所以可以加一个后台符号让它在后台拷就行

&是指在后台运行,但当用户推出(挂起)的时候,命令自动也跟着退出
&的意思是在后台运行, ./a.out & 的时候, 即使你用ctrl C, 那么a.out照样运行(因为对SIGINT信号免疫)。 但是要注意, 如果你直接关掉shell后, 那么, a.out进程同样消失。 可见, &的后台并不硬(因为对SIGHUP信号不免疫)。

nohup的意思是忽略SIGHUP信号, 所以当运行nohup ./a.out的时候, 关闭shell, 那么a.out进程还是存在的(对SIGHUP信号免疫)。
但是如果你直接在shell中用Ctrl C, 那么, a.out进程也是会消失的(因为对SIGINT信号不免疫)

那么,我们可以巧妙的吧他们结合起来用就是
nohup COMMAND &
这样就能使命令永久的在后台执行

Last modification:July 1st, 2020 at 02:05 am
如果觉得我的文章对你有用,请随意赞赏