task_struct

linux中的每个进程都是由一个task_struct数据结构进行描述,即通常所说的“进程控制块,PCB”,容纳了一个进程的所有信息

linux内核中并没有thread这一个概念,所有的线程在linux内核中被看作是标准进程,仅是一个与其他进程共享某些特定资源的进程,每个线程都有独立的task_struct

显示进程状态指令

ps -aux

当使用 ps -aux 时,可以输出当前linux系统的运行的进程的状态快照(即不会动态变化,注意 top 指令会动态刷新)
Image [10].png

  • USER:当前进程的所属用户
  • PID:进程ID
  • %CPU:占用的CPU使用率
  • %MEM:占用的物理内存百分比
  • VSZ:占用的虚拟内存量
  • RSS:占用的固定的内存量
  • TTY:终端的次要装置号码(minor device number of tty),示例中的TTY列都是“?”,是表示这些进程不属于任何TTY,因为它们是由系统启动的,tty1-tty6 是本机上面的登入者程序,若为 pts/0 等等的,则表示为由网络连接进主机的程序。
    Image [11].png
  • STAT:该进程的状态,有下一个板块的几个状态,D,R,S,T,Z是ps指令标识进程的5种状态码

    • R(TASK_RUNNING):正在运行或者可运行。
      而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中)。进程调度器的任务就是从各个CPU的可执行队列中分别选择一个进程在该CPU上运行
    • S(TASK_INTERRUPTIBLE):可中断的睡眠状态
      处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。这些进程的task_struct结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发、或由其他进程触发),对应的等待队列中的一个或多个进程将被唤醒。一般情况下,进程列表中的绝大多数进程都处于TASK_INTERRUPTIBLE状态(除非机器的负载很高)。
      Image [12].png像 epoll_server_write_event_et 就是处于监听socket的状态,因此是 S 状态

    • D(TASK_UNINTERRUPTIBLE):不可中断睡眠
      (通常是在进行IO操作)
      与TASK_INTERRUPTIBLE状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。收到信号不唤醒和不可运行,进程必须等待直到有中断发生,通常是在进行IO操作。kill -9 无法杀死该状态下的进程了!
      该状态的意义在于,使内核的某些流程不可被打断。

    • T(TASK_STOPPED or TASK_TRACED):暂停状态或跟踪状态
      向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态,除非该进程本身处于TASK_UNINTERRUPTIBLE状态而不响应信号。(SIGSTOP与SIGKILL信号一样,是非常强制的。不允许用户进程通过signal系列的系统调用重新设置对应的信号处理函数。向进程发送一个SIGCONT信号,可以让其从TASK_STOPPED状态恢复到TASK_RUNNING状态。
      当进程正在被跟踪时,它处于TASK_TRACED这个特殊的状态。“正在被跟踪”指的是进程暂停下来,等待跟踪它的进程对它进行操作。比如在gdb中对被跟踪的进程下一个断点,进程在断点处停下来的时候就处于TASK_TRACED状态。而在其他时候,被跟踪的进程还是处于前面提到的那些状态。对于进程本身来说,TASK_STOPPED和TASK_TRACED状态很类似,都是表示进程暂停下来。
      而TASK_TRACED状态相当于在TASK_STOPPED之上多了一层保护,处于TASK_TRACED状态的进程不能响应SIGCONT信号而被唤醒。只能等到调试进程通过ptrace系统调用执行PTRACE_CONT、PTRACE_DETACH等操作(通过ptrace系统调用的参数指定操作),或调试进程退出,被调试的进程才能恢复TASK_RUNNING状态。
    • Z(TASK_DEAD - EXIT_ZOMBIE):退出状态,此时为僵尸进程
      进程在退出的过程中,处于TASK_DEAD状态。
      在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。于是进程就只剩下task_struct这么个空壳,故称为僵尸。
      之所以保留task_struct,是因为task_struct里面保存了进程的退出码、以及一些统计信息。而其父进程很可能会关心这些信息。比如在shell中,$?变量就保存了最后一个退出的前台进程的退出码,而这个退出码往往被作为if语句的判断条件。
      当然,内核也可以将这些信息保存在别的地方,而将task_struct结构释放掉,以节省一些空间。但是使用task_struct结构更为方便,因为在内核中已经建立了从pid到task_struct查找关系,还有进程间的父子关系。释放掉task_struct,则需要建立一些新的数据结构,以便让父进程找到它的子进程的退出信息。父进程可以通过wait系列的系统调用(如wait4、waitid)来等待某个或某些子进程的退出,并获取它的退出信息。然后wait系列的系统调用会顺便将子进程的尸体(task_struct)也释放掉。
      子进程在退出的过程中,内核会给其父进程发送一个信号,通知父进程来“收尸”。这个信号默认是SIGCHLD,但是在通过clone系统调用创建子进程时,可以设置这个信号。
    • X(TASK_DEAD - EXIT_DEAD):退出状态,进程即将被销毁
    • < :高优先级
    • N :低优先级
    • L:页面锁定在内存
    • s:进程的领导者(在他之下有子进程)
    • l:多线程
    • +:在后台的进程组
  • TIME:进程已消耗的CPU时间
  • COMMAND:启动进程的命令

ps -ef

Image [13].png

  • PID:进程ID
  • PPID:父进程ID
  • C:CPU占用值
  • STIME:开启时间

ps -lax

Image [14].png

  • F:进程标识
  • NI:谦让度
  • WCHAN:正在等待的进程资源
    Image [15].pngepoll_server_write_event_et 正在等待 SyS_ep

top

Image [16].png

第一行:top命令当前信息
  • 13:42:57 :运行开始时间(top指令是动态刷新)
  • up 3:57 :已运行时间
  • 1 user:当前系统的登录用户
  • load average:0.00, 0.00, 0.00 :1分钟、5分钟、15分钟的平均负载

第二行:任务信息
  • 238 total :当前的总任务数
  • 2 running:正在运行的进程
  • 235 sleeping:休眠中的进程
  • 0 stopped:暂停的进程
  • 1 zombie:僵尸进程

第三行:cpu状态信息
  • 2.0 us(user space):用户控件占用CPU的百分比
  • 3.0 sy(sysctl):内核控件占用CPU的百分比
  • 0.0 ni :改变过优先级的进程占用CPU的百分比
  • 89.8 id(idolt):空闲CPU百分比
  • 5.1 wa(wait):IO等待占用CPU的百分比
  • 0.0 hi(Hardware IRQ):硬中断占用CPU的百分比
  • 0.1 si(Software IRQ):软中断占用CPU的百分比,如果软中断过多,可以使用指令查证软中断类型的统计,然后分析是哪些软中断过多,比如网络软中断NET_RX,就要查证哪个网卡有大量的网络包进来,进而使用tcpdump抓包,分析来源,甄别非法地址,或者硬件升级
  • 0.0 st :当前虚拟机被hypervisor偷去的CPU时间

第四行:内存状态
  • 8160856 total :总内存量
  • 6721228 free :剩余内存量
  • 786512 used :已使用的内存量
  • 653116 buff/cache :缓存的内存量

第五行:swap交换区状态
  • 8384508 total :总交换区大小
  • 8384508 free :剩余交换区大小
  • 0 used :已使用的交换区大小(0表示系统内存足够,不需要使用到swap交换区)
  • 7123088 avail Mem :缓冲的交换区大小

swap 分区是将某块特殊的硬盘空间,需要手动划分,当实际物理内存不够用时,操作系统会从内存中取出一部分暂时不用的数据,放在交换分区,这种做法会使运行效率大大降低。因此要避免使用swap分区,当出现使用时应该加大本机物理内存。
free -m:可以查看物理内存和swap分区的大小和使用情况

第六行:进程状态
  • PID:进程id
  • USER:进程所有者
  • PR:进程优先级
  • NI:nice值(nice值意为“友好”,因此等级越高,执行的优先级更高)。负值表示高优先级,正值表示低优先级。和PR(也是PRI)的区别在于此值时静态的,而PR是动态的,PR_new = PR_old + NI
  • VIRT:进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
    1. 进程需要的虚拟内存大小,包括进程使用的库、代码、数据等
    2. 加入进程申请100m的内存,但是实际只使用了10m,此处的参数还是会增加100m,而不是实际的使用量
  • RES:进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
    1. 进程当前使用的内存大小,不包括swap out
    2. 包含其他进程的共享
    3. 如果申请100m的内存,实际使用10m,该参数只增长10m
  • SHR:共享内存大小,单位kb
    1. 除了自身进程的共享内存,也包括其他进程的共享内存
    2. 虽然进程只是用了几个共享库的函数,但它包含了整个共享库的大小
    3. 计算某个进程所占的物理内存大小公式:RES -SHR
    4. swap out 后,该参数会降下来
  • S:进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
  • %CPU:上次更新到现在的CPU时间占用百分比
  • %MEM:进程使用的物理内存百分比
  • TIME+:进程使用的CPU时间总计,单位1/100秒
  • COMMAND:进程名称(命令名/命令行)