目录
关于进程
什么是进程
程序只是静态的数据,运行起来后才是进程,进程是动态的,有不同的生命周期。进程是已启动的可执行程序的运行实例,运行中的程序的一个副本,一个程序可同时运行多个,例如QQ。
一般应用程序的运行都会发生系统调用(system call)和库 调用(libary call),将特权指令或用户指令发送给CPU。
程序的运行过程不断地在执行用户代码和执行内核代码之间转换。例如1、执行用户代码------>2、提交指令CPU------>3、需要系统调用------>4、软中断------>5、执行内核代码------>6、返回数据给程序------>7、继续执行用户代码
转换到执行内核代码时需要发起软中断,这种转换是需要消耗系统开销的。
进程有以下组成部分:
• 已分配内存的地址空间;
• 安全属性,包括所有权凭据和特权;
• 程序代码的一个或多个执行线程;
• 进程状态
进程的生命周期
父进程复制自己的地址空间(fork)传建一个新的(子)进程结构。每个新进程分配一个唯一的进程ID(PID),满足跟踪安全性之需,PID和父进程(PPID)是子进程环境的元素,任何进程都可以创建子进程,所有进程都是第一个系统进程的后代:
Centos5/6: init 是由内核创建的,其他进程都是它创建或者它创建的进程创建,负责管理进程和创建用户空间,进程号是1。
[root@localhost ~]# pstree
init─┬─auditd───{auditd}
├─crond
├─master─┬─pickup
│ └─qmgr
├─6*[mingetty]
├─mysqld_safe───mysqld───29*[{mysqld}]
├─rsyslogd───3*[{rsyslogd}]
├─sshd─┬─sshd───sftp-server
│ ├─sshd───bash───python───python───{python}
│ └─sshd───bash───pstree
└─udevd───2*[udevd]
Centos7: systemd是由内核创建的,其他进程都是它创建或者它创建的进程创建,负责管理进程和创建用户空间,进程号是1。
[root@localhost ~]# pstree
systemd─┬─ModemManager───2*[{ModemManager}]
├─NetworkManager───2*[{NetworkManager}]
├─VGAuthService
├─2*[abrt-watch-log]
├─abrtd
├─alsactl
├─atd
├─auditd─┬─audispd─┬─sedispatch
│ │ └─{audispd}
│ └─{auditd}
子进程继承父进程的安全性身份、过去和当前的文件描述符,端口和资源特权,环境变量,以及程序代码。随后,子进程可能exec自己的程序代码,通常,父进程在子进程运行期间处于睡眠(sleeping)状态,当子进程完成时发出(exit)信号请求,在退出时,子进程已经关闭或丢弃了其资源环境,剩余的部分称为僵停(僵尸Zombie)。父进程在子进程退出时收到信号而被唤醒,清理剩余的结构,然后继续执行其自己的程序代码。
父进程和子进程开始的时候使用同一块内存空间,一旦子进程需要修改数据,会把父进程的数据复制一份,在拷贝的里面修改数据。(COW 写时复制机制)
父进程创建子进程的目的是为了完成一些复杂的任务,当任务完成后,需要终止或销毁子进程,因此任何子进程的销毁或者终止都是父进程完成的。
进程状态
一个进程运行的顺序大概如此,运行指令只能通过CPU,假设操作系统上面单颗CPU,那怎么同时运行多个进程呢?
在多任务处理操作系统中,每个CPU(或核心)在一个时间点上只能处理一个进程。在进程运行时,它对CPU时间和资源分配的要求会不断变化,从而为进程分配一个状态,它随着环境要求而改变。
操作系统对CPU进行timeslice(时间片)虚拟化处理,每一个时间片内只能处理一个进程,时间结束后,不管是否运行完毕,都要切换到另外一个进程,来回切换直到运行结束,因此进程状态会一直发生变化。
每个CPU(或CPU核心)在一个时间点上只能处理一个进程,通过时间片技术,Linux实际能够运行的进程(和线程数)可以超出实际可用的CPU及核心数量。Linux内核进程调度程序将多个进程在CPU核心上快速切换,从而给用户多个进程在同时运行的印象。
运行态:running
就绪态(也叫睡眠态)::ready
可中断:interruptable
不可中断:uninterruptable
停止态:stopped 暂停于内存中,但不会被调度,除非手动启动之;
僵死态:zombie
进程优先级
多进程执行时,一个时间片结束后,CPU接着该执行哪个进程呢?此时操作系统精巧设计了优先级的概念,通过调度算法来实现进程调度。
1-99称为实时优先级范围
100-139称为普通优先级范围(静态优先级)
显然值越低优先级越高,实时进程的优先级一定在实时优先级范围,普通进程一般在普通优先级范围,但是可以提高到实时优先级范围,但是提高到实时优先级范围的普通进程依然是普通进程!
实时进程永远比普通进程优先调度,获得实时优先级的普通进程,只是说将会比其他的普通进程更有话语权,这里就又涉及到CFS的调度策略了,我们不展开
此外,普通优先级和nice(一个改变优先级的系统调用)值有对应关系,nice=0时优先级对应为120
nice的范围是(-20到19,为什么这么诡异呢,这你就要问写这段代码的人了)
进程结构体
上面讲到通常情况下多个进程根据优先级切换运行,如果有一个进程A运行了一半,切换到B进程,B进程运行一个时间片后,又运行进程A。中间的A进程已经执行的指令和数据应该保存起来,不然这种切换就没有意义了!这一系列动作包括了中断、保持现场、恢复现场的操作。
进程数据包括ID号、占内存大小、消耗时间等进程元数据,以结构体的形式存放在内存中,主要作用是用来记录追踪进程信息。另外为了提高追踪效率,设计了固定格式task struct,多个任务的的task struct组件的链表:task list。前一个结构体记录下一个结构体的地址,或者双向记录,或者首位相连,于是产生了循环链表、双向链表等。
进程内存
Page Frame: 页框,用存储页面数据
Linux采用虚拟内存管理,将实际物理内存切成每块4K大小的 Page Frame,每个进程都以为自己拥有本机的所有内存,但实际上内核只会分配它用到的内存。
内核在给进程分配内存时,分配的是一段线性的虚拟地址,通过映射关系关联到物理地址中(一个或多个Page Frame).
当内存耗尽后,后使用到交换内存swap,内核将通过LRU算法将不用的内存数据放入到交换空间中,腾出多余空间供进程使用。
这样会造成一个问题,数据转入转出会造成实际物理内存地址发生变化,按照以前的映射关系就找不到数据了,形成缺页现象(大小),这个时候需要有一个模块
专门负责维护这个映射关系,实时进行变换。因此CPU里面有一个专门的芯片负责此工作。
MMU:Memory Management Unit
进程内存结构由堆栈组成,下面放程序指令+变量等,上面是数据。
所以进程的内存又可以分为常驻内存级(不可被交换)和虚拟内存级(可被交换)。
进程类型
守护进程: 在系统引导过程中启动的进程,跟终端无关的进程;daemon
前台进程(用户进程):跟终端相关,通过终端启动的进程
注意:也可把在前台启动的进程送往后台,以守护模式运行;
进程分类
CPU-Bound CPU密集型 比如蓝光电影播放
IO-Bound IO密集型 比如编辑器
一般交互的是IO密集型,非交互的CPU密集型。
下面将详细记录与进程相关的命令和工具。