linux操作系统分析

一、 进程管理命令
    Linux下,监控和管理进程的命令有很多,下面我们以ps、top、pstree、lsof四个最常用的指令介绍如果有效的监控和管理linux下的各种进程。


    (1)利用ps命令监控系统进程
ps是linux下最常用的进程监控命令,重点讲述如何利用ps指令监控和管理系统进程。
举例:
下面是apache进程的输出信息
2016216113322165.png (520×255)

其中,UID是用户的ID标识号,PID是进程的标识号,PPID表示父进程,STIME表示进程的启动时间,TTY表示进程所属的终端控制台,TIME表示进程启动后累计使用的CPU总时间,CMD表示正在执行的命令。并且root的PPID为1,即为Init的ID.
    
   另一种指令方式查看子进程与父进程的对应关系:
2016216113342162.png (683×282)

其中,%CPU表示进程占用的CPU百分比,%MEM表示进程占用内存的百分比,VSZ表示进程虚拟大小,RSS表示进程的实际内存(驻留集)大小(单位是页)。
    STAT表示进程的状态,进程的状态有很多种:用“R”表示正在运行中的进程,用“S”表示处于休眠状态的进程,用“Z”表示僵死进程,用“<”表示优先级高的进程,用“N”表示优先级较低的进程,用“s”表示父进程,用“+”表示位于后台的进程。START表示启动进程的时间。
    这个例子将进程之间的关系用树形结构形象的表示出来,可以很清楚的看到,第一个进程为父进程,而其它进程均为子进程。同时从这个输出还可以看到每个进程占用CPU、内存的百分比,还有进程所处的状态等等。


    (2)利用pstree监控系统进程
pstree命令以树形结构显示程序和进程之间的关系,使用格式如下:

pstree [-acnpu] [<PID>/<user>]


具体选项内容可用pstree --help来查看,由于显示结果的树形结构太长,就不再贴图.      
pstree清楚的显示了程序和进程之间的关系,如果不指定进程的PID号,或者不指定用户名称,则将以init进程为根进程,显示系统的所有程序和进程信息,若指定用户或PID,则将以用户或PID为根进程,显示用户或PID对应的所有程序和进程。


    (3)利用top监控系统进程
     top命令是监控系统进程必不可少的工具,与ps命令相比,top命令动态、实时的显示进程状态,而ps只能显示进程某一时刻的信息,同时,top命令提供了一个交互界面,用户可以根据需要,人性化的定制自己的输出,更清楚的了解进程的实时状态。
    下面是top的显示信息
2016216113400420.png (672×374)

通过动态信息可以看出一个进程从上次更新到现在占用cpu时间,占用物理内存(%MEM),从进程启动到现在占用cpu总时间(TIME+)等。通过了解这些信息,可以使系统管理员掌握每个进程对系统CPU、物理内存的使用状况。
  
    (4)利用lsof监控系统进程与程序
lsof全名list opened files,也就是列举系统中已经被打开的文件,通过lsof,我们就可以根据文件找到对应的进程信息,也可以根据进程信息找到进程打开的文件。
lsof指令功能强大,这里介绍“-c,-g,-p,-i”这四个最常用参数的使用。更详细的介绍请参看manlsof或者lsof --help。
1) lsoffilename:显示使用filename文件的进程。
2)lsof -c abc:显示abc进程现在打开的文件
3)lsof -g gid:显示指定的进程组打开的文件情况,使用进程组ID即GID
4)lsof -p PID:PID是进程号,通过进程号显示程序打开的所有文件及相关进程,例如,想知道init进程打开了哪些文件的话,可以执行“lsof-p  1”命令
5)lsof-i :通过监听指定的协议、端口、主机等信息,显示符合条件的进程信息。
例如:
 显示系统中tcp协议对应的25端口进程信息:

 
[root@localhost ~]# lsof-i tcp:25


显示系统中80端口对应的进程信息:

[root@localhost ~]# lsof-i :80


 (5) 计划任务
计划任务就是提前设定的一系列命名,来在特定时间里自动完成,比如一些自动备份,自动关系,自动发邮件,广播之类
计划任务有三个比较重要的命令
1)at安排作业在某一时刻执行一次
2)Batch安排作业在系统负载不重时执行一次
3)Cron安排周期性运行的作业


(6)结束进程
Kill -1重启进程
kill 进程号   结束进程
kill -9强制结束进程


(7) 设置程序的优先级
Niec :指定程序运行优先级别

、进程的转换

(1)运行状态(TASK_RUNNING)
当进程正在被CPU执行,或已经准备就绪随时可由调度程序执行,则称该进程为处于运行状态(running)。进程可以在内核态运行,也可以在用户态运行。当系统资源已经可用时,进程就被唤醒而进入准备运行状态,该状态称为就绪态。这些状态(图中中间一列)在内核中表示方法相同,都被成为处于TASK_RUNNING状态。


(2)可中断睡眠状态(TASK_INTERRUPTIBLE)
当进程处于可中断等待状态时,系统不会调度该进程执行。当系统产生一个中断或者释放了进程正在等待的资源,或者进程收到一个信号,都可以唤醒进程转换到就绪状态(运行状态)。


(3)不可中断睡眠状态(TASK_UNINTERRUPTIBLE)
与可中断睡眠状态类似。但处于该状态的进程只有被使用wake_up()函数明确唤醒时才能转换到可运行的就绪状态。


(4)暂停状态(TASK_STOPPED)
当进程收到信号SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU时就会进入暂停状态。可向其发送SIGCONT信号让进程转换到可运行状态。在Linux 0.11中,还未实现对该状态的转换处理。处于该状态的进程将被作为进程终止来处理。


(5)僵死状态(TASK_ZOMBIE)
当进程已停止运行,但其父进程还没有询问其状态时,则称该进程处于僵死状态。
当一个进程的运行时间片用完,系统就会使用调度程序强制切换到其它的进程去执行。另外,如果进程在内核态执行时需要等待系统的某个资源,此时该进程就会调用sleep_on()或sleep_on_interruptible()自愿地放弃CPU的使用权,而让调度程序去执行其它进程。进程则进入睡眠状态(TASK_UNINTERRUPTIBLE或TASK_INTERRUPTIBLE)。
只有当进程从“内核运行态”转移到“睡眠状态”时,内核才会进行进程切换操作。在内核态下运行的进程不能被其它进程抢占,而且一个进程不能改变另一个进程的状态。为了避免进程切换时造成内核数据错误,内核在执行临界区代码时会禁止一切中断。

三、进程的调度

  Linux O(1)调度器(O(1) scheduler) 是历史上一个流行的Linux系统调度程序。命名为这个名字是因为它能够在常数时间内执行任务调度,例如从执行队列中选择一个任务或将一个任务加入执行队列,这与系统中的任务总数有关。

 (1) O(1)调度器

  在O(1)调度中,要问最重要的数据结构是运行队列。运行队列描绘了进程队列的结构,在内核源码中用runqueue结构体表示。

struct runqueue 
{   unsigned long nr_running; 
    task_t *curr;
    prio_array_t *active,*expired,arrays[2]; 
};

 (2)优先级数组

  O(1)算法的另一个核心数据结构即为prio_array结构体。该结构体中有一个用来表示进程动态优先级的数组queue,它包含了每一种优先级进程所形成的链表。

复制代码
#define
 MAX_USER_RT_PRIO        100
#define
 MAX_RT_PRIO             MAX_USER_RT_PRIO
#define
 MAX_PRIO                (MAX_RT_PRIO + 40)
typedef struct prio_array
 prio_array_t;
struct prio_array
 {
      unsigned int nr_active;
      unsigned long bitmap[BITMAP_SIZE];
      struct list_head
 queue[MAX_PRIO];
};
复制代码

 (3)静态优先级和动态优先级

  进程有两个优先级,一个是静态优先级,一个是动态优先级.静态优先级是用来计算进程运行的时间片长度的,动态优先级是在调度器进行调度时用到的,调度器每次都选取动态优先级最高的进程运行.

静态优先级的计算:
nice值和静态优先级之间的关系是:静态优先级=100+nice+20
而nice值的范围是-20~19,所以普通进程的静态优先级的范围是100~139
动态优先级的计算:
动态优先级=max(100 , min(静态优先级 – bonus + 5 , 139))

 (4)时间片

  O(1)算法采用过期进程数组和活跃进程数组解决以往调度算法所带来的O(n)复杂度问题。过期数组中的进程都已经用完了时间片,而活跃数组的进程还拥有时间片。当一个进程用完自己的时间片后,它就被移动到过期进程数组中,同时这个过期进程在被移动之前就已经计算好了新的时间片。可以看到O(1)调度算法是采用分散计算时间片的方法,并不像以往算法中集中为所有可运行进程重新计算时间片。当活跃进程数组中没有任何进程时,说明此时所有可运行的进程都用完了自己的时间片。那么此时只需要交换一下两个数组即可将过期进程切换为活跃进程,进而继续被调度程序所调度。两个数组之间的切换其实就是指针之间的交换,因此花费的时间是恒定的。

struct prop_array *array = rq->active;
if (array->nr_active != 0) {
    rq->active = rq->expired;
    rq->expired = array;
}

  上面的代码说明了两个数组之间的交换,通过分散计算时间片、交换过期和活跃两个进程集合的方法可以使得O(1)算法在恒定的时间内为每个进程重新计算好时间片。

进程运行的时间片长度的计算
静态优先级<120,基本时间片=max((140-静态优先级)*20, MIN_TIMESLICE)
静态优先级>=120,基本时间片=max((140-静态优先级)*5, MIN_TIMESLICE)

 (5)调度算法

  

在每次进程切换时,内核依次扫描就绪队列上的每一个进程,计算每个进程的优先级,再选择出优先级最高的进程来运行;尽管这个算法理解简单,但是它花费在选择优先级最高进程上的时间却不容忽视。系统中可运行的进程越多,花费的时间就越大,时间复杂度为O(n)。

//伪代码
for (系统中的每个进程) {
    重新计算时间片;
    重新计算优先级;
}

 

对操作系统进程模型的看法

操作系统线程模型不会一成不变,而是变得越来越完善,创新是最好的生产力,不同模型的消耗,算法和用户体验是不同的,模型的固定限制着技术的发展,我相信在不久的将来,此模型会迎来大的变革,计算机技术将会跨越一个新的时代。

五、参考

http://www.jb51.net/LINUXjishu/429990.html

https://blog.csdn.net/cosmoslhf/article/details/41486965

https://blog.csdn.net/qq_33650978/article/details/53559835

猜你喜欢

转载自www.cnblogs.com/nirui/p/8977538.html