当 Linux OOM Killer 中断进程时,内核日志通常会提供有关罪魁祸首的内存消耗的足够信息(即使它最终没有被杀死)。例如,当snmpd
进程成为 OOM 触发器时,稍后可以通过以下方式在日志中找到其内存状态PID=1190
:
Jul 18 02:21:26 inm-agg kernel: snmpd invoked oom-killer: gfp_mask=0x100cca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0
Jul 18 02:21:26 inm-agg kernel: CPU: 3 PID: 1190 Comm: snmpd Kdump: loaded Not tainted 5.4.17-2102.201.3.el8uek.x86_64 #2
...
Jul 18 02:21:26 inm-agg kernel: Tasks state (memory values in pages):
Jul 18 02:21:26 inm-agg kernel: [ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name
...
Jul 18 02:21:26 inm-agg kernel: [ 1190] 0 1190 78491 1761 217088 0 0 snmpd
然而,当同样的情况发生在 Java 应用程序的线程上时(OpenJDK 64-Bit Server VM (build 25.372-b07, mixed mode)
在我的例子中),日志包含一个与任何进程都不对应的PID 。例如,在以下日志中,Apache Cassandra 的输入处理线程ReadStage-150
已成为 OOM 触发器:
Jul 16 22:01:45 inm-agg kernel: ReadStage-150 invoked oom-killer: gfp_mask=0x100dca(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), order=0, oom_score_adj=0
Jul 16 22:01:45 inm-agg kernel: CPU: 11 PID: 1653163 Comm: ReadStage-150 Kdump: loaded Not tainted 5.4.17-2102.201.3.el8uek.x86_64 #2
但PID=1653163
消息中指定的内容没有在其他地方提到:
$ journalctl -k -b -e | grep "1653163" | wc -l
1
它与 Java 进程 PID 本身没有任何共同点(1652432
):
Jul 16 22:01:45 inm-agg kernel: Tasks state (memory values in pages):
Jul 16 22:01:45 inm-agg kernel: [ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name
…
Jul 16 22:01:45 inm-agg kernel: [1652432] 0 1652432 7256008 5839621 49709056 0 0 java
所以我想知道:
- oom-killer消息的PID来自哪里?
- 在这种情况下,为什么线程与其托管 JVM 进程分开处理?
- 如果将 oom-killer 配置为杀死 OOM 发起者,是否有可能(至少在理论上)仅中断罪魁祸首线程而不是整个 JVM?