文章目录
-
重要:本系列文章内容摘自
<Linux内核深度解析>
基于ARM64架构的Linux4.x内核一书,作者余华兵。系列文章主要用于记录Linux内核的大部分机制及参数的总结说明
1 内存耗尽杀手
当内存严重不足的时候,页分配器在多次尝试直接页回收失败以后,就会调用内存耗尽杀手(OOM killer,OOM是“Out of Memory”的缩写),选择进程杀死,释放内存:
1.1 使用方法
内存耗尽杀手没有配置宏,可配置的参数如下:
(1)/proc/sys/vm/oom_kill_allocating_task:是否允许杀死正在申请分配内存并触发内存耗尽的进程,避免扫描进程链表选择进程,非零值表示允许,0表示禁止,默认禁止。
(2)/proc/sys/vm/oom_dump_tasks:是否允许内存耗尽杀手杀死进程的时候打印所有用户进程的内存使用信息,非零值表示允许,0表示禁止,默认允许。
(3)/proc/sys/vm/panic_on_oom:是否允许在内存耗尽的时候内核恐慌(panic),重启系统。0表示禁止内核恐慌;1表示允许内核恐慌,但是如果进程通过内存策略或cpuset限制了允许使用的内存节点,这些内存节点耗尽内存,不需要重启系统,可以杀死进程,因为其他内存节点可能有空闲的内存;2表示强制执行内核恐慌。默认值是0。如果把参数panic_on_oom设置成非零值,优先级比参数oom_kill_allocating_task高。
内存耗尽杀手计算进程的坏蛋分数(badness score),选择坏蛋分数最高的进程,坏蛋分数的范围是0~1000,0表示不杀死,1000表示总是杀死。管理员可以通过文件“/proc/ /oom_score_adj”为指定进程设置分数调整值,取值范围是1000~1000,值越大导致坏蛋分数越高,分数调整值1000将会导致坏蛋分数是0,表示禁止杀死本进程。
可以通过文件“/proc//oom_score”查看指定进程的坏蛋分数。
1.2 技术原理
内存耗尽杀手分为全局的内存耗尽杀手和内存控制组的内存耗尽杀手。内存控制组的内存耗尽杀手是指内存控制组的内存使用量超过硬限制的时候,从内存控制组选择进程杀死,下面将介绍内存控制组的内存耗尽杀手。全局的内存耗尽杀手是指内存严重不足的时候,从整个系统选择进程杀死。本节只介绍全局的内存耗尽杀手。
内存耗尽杀手的核心函数是out_of_memory,执行流程如下所示:
(1)调用函数check_panic_on_oom,检查是否允许执行内核恐慌,如果允许,那么重启系统。
(2)如果允许杀死正在申请分配内存并触发内存耗尽的进程,那么杀死当前进程。
(3)调用函数select_bad_process,选择坏蛋进程。
(4)调用函数oom_kill_process,杀死坏蛋进程。
函数select_bad_process负责选择坏蛋进程,遍历进程链表,调用函数oom_evaluate_task计算进程的坏蛋分数,选择坏蛋分数最高的进程。
函数oom_badness负责计算进程的坏蛋分数,坏蛋分数的范围是0~1000,0表示不杀死,1000表示总是杀死:
mm/oom_kill.c
unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
const nodemask_t *nodemask, unsigned long totalpages)
{
long points;
long adj;
if (oom_unkillable_task(p, memcg, nodemask))
return 0;
p = find_lock_task_mm(p);
if (!p)
return 0;
adj = (long)p->signal->oom_score_adj;
if (adj == OOM_SCORE_ADJ_MIN ||
test_bit(MMF_OOM_SKIP, &p->mm->flags) ||
in_vfork(p)) {
task_unlock(p);
return 0;
}
points = get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS) +
atomic_long_read(&p->mm->nr_ptes) + mm_nr_pmds(p->mm);
task_unlock(p);
if (has_capability_noaudit(p, CAP_SYS_ADMIN))
points -= (points * 3) / 100;
adj *= totalpages / 1000;
points += adj;
return points > 0 ? points : 1;
}
函数oom_kill_process负责杀死坏蛋进程,执行流程如下:
(1)如果被选中的进程有子进程,那么从所有子进程中选择坏蛋分数最高的子进程代替父进程牺牲,试图使丢失的工作数量最小化。
假设有一个服务器进程,每当一个客户端连接进来,创建一个子进程负责和特定的客户端通信。如果杀死服务器进程,将会导致客户端无法连接进来;如果杀死一个子进程,只影响一个客户端,影响面小。
(2)向被选中的进程发送杀死信号SIGKILL。
总结
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于 java开发 的学习思路及方向。从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的 点击我的Gitee获取。
还有 高级java全套视频教程 java进阶架构师 视频+资料+代码+面试题!
全方面的java进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。