标签:进程
进程:运行中的程序
假设我们要执行mkdir命令,首先我们的系统会去硬盘上读取mkdir这条命令的程序存放在内存中,然后cpu依次执行每条指令,但是有些指令用户空间是无法执行的,比如我们的mkdir必然涉及到硬盘的操作,此时当指令执行到对硬盘的操作的时候,mkdir进程会通过系统调用,向内核申请操作,此时,mkdir进程从cpu上退出,内核进程占用cpu执行硬盘操作,完毕后继续回来执行mkdir进程。
但是内核进程操作完毕后怎么知道从哪里继续mkdir进程的指令呢?其实内核在内存为每个进程维护了一个数据结构叫task structure,纪录了进程各种属性信息,比如pid、ppid等等,内核更新task structure的过程叫保存现场,读取task structure的过程叫恢复现场
我们知道程序有大有小,假如让它们自主分配内存的话将会导致很多问题,比如程序如何得知有哪些内存地址尚未被使用?等等。为了解决这个问题,内核引入线性内存的概念。默认每个进程都认为系统有4G内存空间,最底下的1G给内核用,进程彼此之间独立,认为当前系统上只有内核和进程自己本身两个进程,每个进程都可以申请3G内存,而这3G内存的地址则可以相同。
为了实现这个功能,内核把内存地址分成相同大小的单元,并在每个进程的task structure中额外维护有一张地址转换表,这个表记录进程线性地址与逻辑地址之间的转换关系,事实上,这张表还记录有额外的信息,看下图:
forbidden:此段是禁用的,这是内核自己腾出来的空间
program text:这段记录了程序的指令,而指令是不允许修改的,所以这也是只读段
.data和.bss:记录了程序的数据段
heap:堆,假设我们读取一个文件,我们必须把文件的内容读取到内存中,也就是这里的堆段,但是堆是逻辑概念,实际上的过程是内核发现堆增长了就查找空闲内存分配给堆,然后把文件读取进来
stack:栈,定义了本地变量,全局变量一般在.data里面定义,栈向下增长,堆向上,中间是程序Memory....libraries之间的共享库
我们知道Memory....libraries是进程间的共享库,那么当我们计算一个进程占用的空间大小的时候是否要把这段计算进去呢?计算与不计算都不是我们想要的结果,于是我们在计算进程占用内存大小的时候通常提供两个值rss(不计算)和vsz(计算)
注意:rss指的是常驻内存集,所以计算的是那些不被内存空间交换出去的数据大小(指令等等),vsz则计算的是包括共享库在内的内存占用空间。
类似地,进程的时间也有在cpu上运行的时间和挂钟时间(从进程生成到现在)的概念
进程的并行执行:
假设我们拥有多cpu或者cpu有多核心,那么我们的进程可否同时在两颗cpu上执行?答案是否定的,同一个进程同一时间只能在一个cpu上运行,它的指令有先后关系。但是可以在多个cpu上同时运行多个不同进程。
但是如果一个程序的是并行编程的结果的话,它的进程可以被分成多个线程流,而多个线程之间则可以在不同的cpu上执行,这就实现了同一进程在不同cpu上并行执行,比如数据库,它的查询操作可以做成多个线程流,因为彼此之间互不影响,这样做的其他好处是多个线程可以同享一些资源,比如数据库列表,如果采用多进程模型的话则需要打开多次,而采用多线程模型则只需打开一次作为共享资源,大大节约了内存空间。这样看来是不是多线程模型就一定比多进程模型好呢?答案是否定的,多进程模型对资源的操作是互相独立的,比如写操作(因为每个进程都有自己的内存空间,这里的写操作并不会马上影响磁盘上的数据)等等,而多线程模型则必须对资源进行分配给线程操作,给资源加锁,还要监控锁的释放等等。所以使用多线程还是多进程模型要根据实际情况来。
进程的状态:
ready:表示进程已经准备好,被内核调度即可执行
Executing:执行中
Uninterruptible:不可中断的睡眠态,这意味着计算此时内核把进程调度到cpu也不能执行,比如进程要到io请求数据,但是此时还没准备。
interruptible:可中断的睡眠态,类似ready,内核调度即可执行
zombie:僵尸态,进程结束,但是所占的内存无法释放,比如因为某个意外内核维护的这个进程的task structure丢失,导致内核无从得知进程占用了哪些物理内存。如果一个系统内有很多僵死进程的话,那么我们就可能出现明明类似内存4G明明只使用了2G却一直提示内存不足的情况
进程的优先级:
linux的优先级有0-139共140种,数字越小,优先级越高
100-139:用户可控制
0-99:内核调整
进程的优先级有高有低,一般我们需要先执行优先级高的进程,但是当我们的系统同时来了一大堆进程的时候,我们怎么快速地从中挑选出一个呢,如果按照一般的排队规则,系统光是排队就要消耗一大堆时间,这显然不是我们想要的,于是我们的linux内核2.6引入一种机制,linux按优先级给进程维持140个队列,每生成一个进程按优先级放入不同的队列中,当cpu时间到,从优先级高的队列往低的扫描,这样最多只需要扫描140次。
这里介绍几个算法常用的标准:
O:
O(1):不管队列长度为多少,挑选的时间都一样
O(n):随着队列长度增长,挑选时间成线性增长,即y=x
O(logn)
O(n^2)
O(2^n)
因此当我们想让某个进程优先处理,可以把它放在优先级较高的队列中。当一个进程的优先级比较高的时候意味着它拥有两个特性:
1.更多的cpu运行时间
2.更优先获得运行时间
linux可以通过修改进程的nice值来修改优先级,nice值越高,优先级越低,它们与队列的对于关系如下
nice值:
-20--19
100--139
普通用户仅能调大nice值
/proc 目录里面的数字对应每个进程的ID,进程对应的相关属性在里面修改
进程的分类:
跟终端相关的进程
跟终端无关的进程
进程相关命令:
ps:process status
sysV风格:需要加-
e:显示所有线程
l:长格式
f或F:更详细的信息
o:显示指定字段
bsd风格:不需要加-
a:所有与终端有关的进程
u:显示更详细的信息USER、%CPU等
x:所有与终端无关的进程
ps命令的stat字段:
D:不可中断的睡眠
R:运行状态
S:可中断的睡眠
T:停止
z:僵死
<:高优先级
N:低优先级
+:前台进程
l:多线程进程
s:会话进程首进程
ps的COMMAN字段里面要是加[]代表这个是内核线程
pstree:显示进程树
pgrep:
pidof:查找运行中程序的id号
top:
cpu字段:
us:user space 用户占用的百分比
sy:system 内核占用...
ni:调整nice值后所占用的百分比
id:idle 空闲
wa:wait 等待
hi:hard interrupt硬件中断所。。
si:soft interrupt 软中断
st:stolen 偷走的,跟虚拟化相关
M:根据驻留内存大小进行排序
P:根据cpu使用百分比进行排序
T:根据累计时间进行排序
l:是否显示平均负载和启动时间
t:是否显示进程和cpu状态相关信息
m:是否显示内存相关信息
c:是否显示完整的命令行信息
q:退出top
k:终止某个进程
top
-d:指定延迟时长,单位是秒
-b:批模式
-n #:在批模式下,共显示多少批
进程间通信(IPC inter Process Communication)方式:
共享内存
信号:Signal
Semaphore:旗语
kill
l:显示所有信号
重要的信号:
1:SIGHUP 让一个进程不用重启就可以重读配置,并生效
2:SIGINT Ctrl+c 中断
9:SIGKILL 杀死一个进程
15:SIGTERM 终止一个进程(与9的区别,留时间给进程处理类似打开文件等处理,也是默认选项)
指定一个信号:
信号号码:kill -1
信号名称:kill -SIGKILL 如:kill -SIGINT
信号名称简写: kill -KILL 如: kill -INT
kill PID
kill %JOBID:终止某作业
killall COMMAND
killall指定信号的方法跟kill一样
调整nice值:
调整已经启动的进程的nice值:
renice NI PID
在启动时指定nice值:
nice -n NI COMMADN
bg和fg:
前台:占据了命令提示符
后台:启动之后释放命令提示符,后续的操作在后台完成
前台-->后台
Ctrl+z:把正在前台运行的作业送到后台
COMMAND &:让命令在后台运行
bg:让后台的停止作业继续运行
bg [[%]jobid]
jobs:查看后台的所有作业
作业号,不同于进程号,kill %2杀死的是作业号
+:命令将默认操作的作业
-:命令将第二个默认操作的作业
fg:把后台作业调回前台运行
fg [[%]JOBID]
本文出自 “单季稻” 博客,谢绝转载!
标签:进程
原文地址:http://linzb.blog.51cto.com/5192423/1784308