进程优先级起作用的方式从发明以来基本没有什么变化,无论是只有一个cpu的时代,还是多核cpu时代,都是通过控制进程占用cpu时间的长短来实现的。

就是说在同一个调度周期中,优先级高的进程占用的时间长些,而优先级低的进程占用的短些。

请大家真的不要混淆了系统中的这两个概念:nice(NI)和priority(PR),他们有着千丝万缕的关系,但对于当前的Linux系统来说,它们并不是同一个概念。

什么是NICE值?

NICE值应该是熟悉Linux/UNIX的人很了解的概念了,它是反应一个进程“优先级”状态的值,其取值范围是-20至19,一共40个级别。

这个值越小,表示进程”优先级”越高,而值越大“优先级”越低。

例如,我们可以通过NICE命令来对一个将要执行的bash命令进行NICE值设置,方法是:

  1. [root@zorrozou-pc0 zorro]# nice -n 10 bash

这样我就又打开了一个bash,并且其nice值设置为10,而默认情况下,进程的优先级应该是从父进程继承来的,这个值一般是0。

nice值虽然不是priority,但是它确实可以影响进程的优先级。

在英语中,如果我们形容一个人nice,那一般说明这个人的人缘比较好。什么样的人人缘好?往往是谦让、有礼貌的人。

比如,你跟一个nice的人一起去吃午饭,点了两个一样的饭,先上了一份后,nice的那位一般都会说:“你先吃你先吃!”,这就是人缘好,这人nice!但是如果另一份上的很晚,那么这位nice的人就要饿着了。

这说明什么?

越nice的人抢占资源的能力就越差,而越不nice的人抢占能力就越强。这就是nice值大小的含义,nice值越低,说明进程越不nice,抢占cpu的能力就越强,优先级就越高(作者这个解释太形象了,小编忍不住要手动点赞!!)。

在原来使用O1调度的Linux上,我们还会把nice值叫做静态优先级,这也基本符合nice值的特点,就是当nice值设定好了之后,除非我们用renice去改它,否则它是不变的。

而priority的值在之前内核的O1调度器上表现是会变化的,所以也叫做动态优先级

什么是优先级和实时进程?

我们再来看看什么是priority值,就是ps命令中看到的PRI值或者top命令中看到的PR值。

本文为了区分这些概念,以后:

  • 统一用nice值表示NI值,或者叫做静态优先级,也就是用nice和renice命令来调整的优先级;
  • 而实用priority值表示PRI和PR值,或者叫动态优先级。
  • 我们也统一将“优先级”这个词的概念规定为表示priority值的意思

说白了就是,Linux实际上实现了140个优先级范围,取值范围是从0-139,这个值越小,优先级越高。nice值的-20到19,映射到实际的优先级范围是100-139。

新产生进程的默认优先级被定义为:

  1. #define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2)

实际上对应的就是nice值的0。

正常情况下,任何一个进程的优先级都是这个值,即使我们通过nice和renice命令调整了进程的优先级,它的取值范围也不会超出100-139的范围,除非这个进程是一个实时进程,那么它的优先级取值才会变成0-99这个范围中的一个。

所有优先级值在0-99范围内的,都是实时进程,所以这个优先级范围也可以叫做实时进程优先级,而100-139范围内的是非实时进程。

系统的整体优先级策略是:

  • 如果系统中存在需要执行的实时进程,则优先执行实时进程。
  • 直到实时进程退出或者主动让出CPU时,才会调度执行非实时进程。

实时进程可以指定的优先级范围为1-99,将一个要执行的程序以实时方式执行的方法为:

  1. [root@zorrozou-pc0 zorro]# chrt 10 bash
  2. [root@zorrozou-pc0 zorro]# chrt -p $$
  3. pid 14840's current scheduling policy: SCHED_RR
  4. pid 14840's current scheduling priority: 10

可以看到,新打开的bash已经是实时进程,默认调度策略为SCHED_RR,优先级为10。如果想修改调度策略,就加个参数:

  1. [root@zorrozou-pc0 zorro]# chrt -f 10 bash
  2. [root@zorrozou-pc0 zorro]# chrt -p $$
  3. pid 14843's current scheduling policy: SCHED_FIFO
  4. pid 14843's current scheduling priority: 10

linux下允许程序申请比系统可用内存更多的内存,这个特性叫Overcommit。这样做是出于优化系统考虑,因为不是所有的程序申请了内存就立刻使用的,当你使用的时候说不定系统已经回收了一些资源了。不幸的是,当你用到这个Overcommit给你的内存的时候,系统还没有资源的话,OOM killer就跳出来了。

参数/proc/sys/vm/overcommit_memory可以控制进程对内存过量使用的应对策略
1.当overcommit_memory=0 允许进程轻微过量使用内存,但对于大量过载请求则不允许,也就是当内存消耗过大就是触发OOM killer。
2.当overcommit_memory=1 永远允许进程overcommit,不会触发OOM killer。
3.当overcommit_memory=2 永远禁止overcommit,不会触发OOM killer。

当然,如果触发了OOM机制,系统会杀掉某些进程,那么什么进程会被处理掉呢?kernel提供给用户态的/proc下的一些参数:
1./proc/[pid]/oom_adj,该pid进程被oom killer杀掉的权重,介于 [-17,15](具体具体权重的范围需要查看内核确认)之间,越高的权重,意味着更可能被oom killer选中,-17表示禁止被kill掉。

通过2个步骤可以确认,具体权重的范围:

①uname -a查看Linux内核版本

②进入/usr/src/kernels/内核版本/include/linux/oom.h确认具体的权重范围

2./proc/[pid]/oom_score,当前该pid进程的被kill的分数,越高的分数意味着越可能被kill,这个数值是根据oom_adj运算(2ⁿ,n就是oom_adj的值)后的结果。

oom_adj,oom_score是oom_killer的主要参考值

 
So(我们能做什么):
1.保护我们重要的进程,避免被处理掉
实例:
ps -ef|grep GameServer(获得重要进程的PID)
echo -17 > /proc/PID/oom_score_adj(输入-17,禁止被OOM机制处理)
2.关闭OOM机制(不推荐,如果不启动OOM机制,内存使用过大,会让系统产生很多异常数据)
echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
systcl -p
 

vm.panic_on_oom    默认为0开启    为1时表示关闭此功能

等于0时,表示当内存耗尽时,内核会触发OOM killer杀掉最耗内存的进程。

当OOM Killer被启动时,通过观察进程自动计算得出各当前进程的得分 /proc/<PID>/oom_score,分值越高越容易被kill掉。

05-12 20:38