業務中に Linux の OOM キラーの dmesg を見ていたら、見慣れない形式のログがあったので調べてみた
ログ
こんなログです
May 23 02:06:26 **** kernel: [40872.663481] Memory cgroup out of memory: OOM victim 46452 (nginx) is already exiting. Skip killing the task
〜 is already exiting. Skip killing the task
というメッセージは見たことがなかったので調べました。
ソースを調べる
該当のメッセージを grep するとすぐに見つかりました。__oom_kill_process() で出力しています。
static void __oom_kill_process(struct task_struct *victim, const char *message) { struct task_struct *p; struct mm_struct *mm; bool can_oom_reap = true; p = find_lock_task_mm(victim); if (!p) { pr_info("%s: OOM victim %d (%s) is already exiting. Skip killing the task\n", message, task_pid_nr(victim), victim->comm); put_task_struct(victim); return; } else if (victim != p) { get_task_struct(p); put_task_struct(victim); victim = p; } ... 略
OOM でプロセスを止める際、task_struct -> mm_struct が参照できない場合に出力されるログのようですね。プロセスが止まる処理と OOM キラーで止めるタイミングがかぶると出るんだろう。
コミットを探す
git blame ですぐに見つかりました。コミットで追加されている。
5.9 で入ったのかな
コミットログは下記のとおりです
When the OOM killer finds a victim and tryies to kill it, if the victim is already exiting, the task mm will be NULL and no process will be killed. But the dump_header() has been already executed, so it will be strange to dump so much information without killing a process. We'd better show some helpful information to indicate why this happens.
翻訳しておきます
OOMキラーが犠牲者を見つけ、それを殺そうとするとき、犠牲者がすでに終了していれば、タスクmmはNULLになり、プロセスは殺されない。 しかし、dump_header()はすでに実行されているので、プロセスを殺さずに多くの情報をダンプするのは奇妙である。 なぜこのようなことが起こるのかを示すために なぜこのようなことが起こるのかを示すために、有益な情報を示す必要がある。
DeepL での翻訳
なるほどなぁ。
dump_header()
下記のような実装です
static void dump_header(struct oom_control *oc, struct task_struct *p) { pr_warn("%s invoked oom-killer: gfp_mask=%#x(%pGg), order=%d, oom_score_adj=%hd\n", current->comm, oc->gfp_mask, &oc->gfp_mask, oc->order, current->signal->oom_score_adj); if (!IS_ENABLED(CONFIG_COMPACTION) && oc->order) pr_warn("COMPACTION is disabled!!!\n"); dump_stack(); if (is_memcg_oom(oc)) mem_cgroup_print_oom_meminfo(oc->memcg); else { __show_mem(SHOW_MEM_FILTER_NODES, oc->nodemask, gfp_zone(oc->gfp_mask)); if (should_dump_unreclaim_slab()) dump_unreclaimable_slab(); } if (sysctl_oom_dump_tasks) dump_tasks(oc); if (p) dump_oom_summary(oc, p); }
おそらくは、dmesg に invoked oom-killer のログが出ていたが、その後にプロセスの詳細が出ていなくて混乱を招いたケースがあったのでしょうね。