前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何使用eBPF监控Linux内存 OOM killer:Linux内存调优之eBPF监控内存 OOM killer 事件

如何使用eBPF监控Linux内存 OOM killer:Linux内存调优之eBPF监控内存 OOM killer 事件

作者头像
山河已无恙
发布于 2025-05-19 03:56:06
发布于 2025-05-19 03:56:06
19100
代码可运行
举报
文章被收录于专栏:山河已无恙山河已无恙
运行总次数:0
代码可运行

写在前面


  • 博文内容涉及 使用 eBPF 监控内存 OOM killer 事件,并且采集当前系统的部分相关指标数据
  • 介绍了传统的监控方式以及使用 BPF/eBPF 的方式
  • 关于 OOM killer 是什么,以及对应的内核调优参数,博客没有涉及
  • 理解不足小伙伴帮忙指正 :),生活加油

知不可乎骤得,托遗响于悲风 ---《赤壁赋》


下面实验用的 Linux 环境

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@developer ~]# hostnamectl 
 Static hostname: developer
       Icon name: computer-vm
         Chassis: vm
      Machine ID: 7ad73f2b5f7046a2a389ca780f472467
         Boot ID: cef15819a5c34efa92443b6eff608cc9
  Virtualization: kvm
Operating System: openEuler 22.03 (LTS-SP4)
          Kernel: Linux 5.10.0-250.0.0.154.oe2203sp4.aarch64
    Architecture: arm64
 Hardware Vendor: OpenStack Foundation
  Hardware Model: OpenStack Nova
[root@developer ~]# 

下面我们谈到的 BPF 或者 eBPF 代指整个 BPF/eBPF 技术

OOM Killer 事件: OOM Killer(Out-Of-Memory Killer)是内核在系统内存严重不足时触发的紧急机制,通过终止进程释放内存以维持系统稳定,每个进程有一个 OOM 相关的分数,终止进程的时候基于这个分数进行处理,有一些内核参数可以控制 OOM Killer 的行为,生产中考虑QOS可以进行相关的配置,当然更合理的方式是使用Cgroup对不同进程的内存资源进行限制,这里不多讲,包括 OOM killer 打分机制等等感兴趣的小伙伴可以了解下。

传统的 OOM Killer 内存事件监控

传统的 OOM killer 历史数据查看一般通过内核日志,或者是Cgroup 内存子系统的事件计数器。

Cgroup 内存子系统有 OOM 相关的事件统计, memory.events 指标,是一个内存事件计数器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/system.slice/tuned.service/memory.events
low 0
high 0
limit_in_bytes 0
oom 0
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$

具体的参数指标说明:

  • low: 低内存压力事件次数
  • high: 高内存压力事件次数
  • limit_in_bytes: 达到内存限制的次数
  • oom: OOM(内存耗尽)触发次数。全为 0 表示无相关事件发生。

内核日志dmesg 可以显示详细的 OOM killer 进程相关数据

下面的日志:系统因内存耗尽触发了 OOM Killer,终止了 stress-ng 进程(PID 39693)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@liruilongs.github.io ~]# dmesg -T | grep -A 30  -i "Killed process 39693"
[511 15:41:12 2025] Out of memory: Killed process 39693 (stress-ng) total-vm:2410396kB, anon-rss:1896300kB, file-rss:4kB, shmem-rss:60kB, UID:0 pgtables:3772kB oom_score_adj:1000
[511 15:41:13 2025] stress-ng invoked oom-killer: gfp_mask=0x100dca(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), order=0, oom_score_adj=1000
[511 15:41:13 2025] CPU: 0 PID: 39692 Comm: stress-ng Kdump: loaded Not tainted 5.10.0-250.0.0.154.oe2203sp4.aarch64 #1
[511 15:41:13 2025] Hardware name: OpenStack Foundation OpenStack Nova, BIOS 0.0.0 02/06/2015
[511 15:41:13 2025] Call trace:
[511 15:41:13 2025]  dump_backtrace+0x0/0x214
[511 15:41:13 2025]  show_stack+0x20/0x2c
[511 15:41:13 2025]  dump_stack+0xf0/0x138
[511 15:41:13 2025]  dump_header+0x50/0x1b0
[511 15:41:13 2025]  oom_kill_process+0x258/0x270
[511 15:41:13 2025]  out_of_memory+0xf4/0x3b0
[511 15:41:13 2025]  __alloc_pages+0x1024/0x1214
[511 15:41:13 2025]  alloc_pages_vma+0xb4/0x3e0
[511 15:41:13 2025]  do_anonymous_page+0x1d4/0x784
[511 15:41:13 2025]  handle_pte_fault+0x19c/0x240
[511 15:41:13 2025]  __handle_mm_fault+0x1bc/0x3ac
[511 15:41:13 2025]  handle_mm_fault+0xf4/0x260
[511 15:41:13 2025]  do_page_fault+0x184/0x464
[511 15:41:13 2025]  do_translation_fault+0xb8/0xe4
[511 15:41:13 2025]  do_mem_abort+0x48/0xc0
[511 15:41:13 2025]  el0_da+0x44/0x80
[511 15:41:13 2025]  el0_sync_handler+0x68/0xc0
[511 15:41:13 2025]  el0_sync+0x160/0x180
[511 15:41:13 2025] Mem-Info:
[511 15:41:13 2025] active_anon:4575 inactive_anon:1652614 isolated_anon:0
                             active_file:21 inactive_file:34 isolated_file:0
                             unevictable:1551 dirty:0 writeback:0
                             slab_reclaimable:5171 slab_unreclaimable:10557
                             mapped:2877 shmem:10220 pagetables:6130 bounce:0
                             free:14963 free_pcp:25 free_cma:0
[511 15:41:13 2025] Node 0 active_anon:18300kB inactive_anon:6610456kB active_file:76kB inactive_file:132kB unevictable:6204kB isolated(anon):0kB isolated(file):0kB mapped:11508kB dirty:0kB writeback:0kB shmem:40880kB shmem_thp: 0kB shmem_pmdmapped: 0kB anon_thp: 3829760kB writeback_tmp:0kB kernel_stack:6384kB all_unreclaimable? yes
[root@liruilongs.github.io ~]# 

dmesg 日志来看,系统因内存耗尽触发了 OOM Killer,终止了 stress-ng 进程(PID 39693),内核日志可以看到详细的数据信息,

下面是日志中内存触发条件,也就是相关的第一条日志

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[511 15:41:12 2025] Out of memory: Killed process 39693 (stress-ng) 
total-vm:2410396kB, anon-rss:1896300kB, file-rss:4kB, shmem-rss:60kB, 
UID:0 pgtables:3772kB oom_score_adj:1000

这条日志对应字段的含义:

  • total-vm:2410396kB:进程申请的总虚拟内存为 2.4GB(含物理内存和交换空间)
  • anon-rss:1896300kB:实际占用的匿名内存(堆/栈)为 1.8GB, rss 说明是驻留的物理内存
  • file-rss:4kB: 该进程当前通过文件映射占用了 4KB 物理内存(进程通过 mmap() 映射文件)
  • shmem-rss:60kB : 该进程当前通过共享内存占用了 60KB 物理内存(共享内存通常通过 shmget()tmpfs`(如 /dev/shm)实现)
  • UID:0 : 0 表示 root 用户
  • pgtables:3772kB: 该进程的页表占用了约 3.7MB 内存
  • oom_score_adj:1000:进程的 OOM 评分为最高(1000),因此被内核选为牺牲者。

下面的是 对应的函数调用栈:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[511 15:41:13 2025] Call trace:
[511 15:41:13 2025]  dump_backtrace+0x0/0x214
[511 15:41:13 2025]  show_stack+0x20/0x2c
[511 15:41:13 2025]  dump_stack+0xf0/0x138
[511 15:41:13 2025]  dump_header+0x50/0x1b0
[511 15:41:13 2025]  oom_kill_process+0x258/0x270
[511 15:41:13 2025]  out_of_memory+0xf4/0x3b0
[511 15:41:13 2025]  __alloc_pages+0x1024/0x1214   # 尝试分配物理页失败
[511 15:41:13 2025]  alloc_pages_vma+0xb4/0x3e0
[511 15:41:13 2025]  do_anonymous_page+0x1d4/0x784  # 匿名页分配失败
[511 15:41:13 2025]  handle_pte_fault+0x19c/0x240   # 页表项错误处理
[511 15:41:13 2025]  __handle_mm_fault+0x1bc/0x3ac
[511 15:41:13 2025]  handle_mm_fault+0xf4/0x260
[511 15:41:13 2025]  do_page_fault+0x184/0x464
[511 15:41:13 2025]  do_translation_fault+0xb8/0xe4
[511 15:41:13 2025]  do_mem_abort+0x48/0xc0
[511 15:41:13 2025]  el0_da+0x44/0x80
[511 15:41:13 2025]  el0_sync_handler+0x68/0xc0
[511 15:41:13 2025]  el0_sync+0x160/0x180
...

函数调用栈下部分为内存分配失败 触发 进程 OOM 以及 oom_kill_process 的调用触发 内存杀手,后面部分为一些日志转储的操作。

下面为发生 OOM Kill 时候系统全局内存状态

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[511 15:41:13 2025] Mem-Info:
[511 15:41:13 2025] active_anon:4575 inactive_anon:1652614 isolated_anon:0
                             active_file:21 inactive_file:34 isolated_file:0
                             unevictable:1551 dirty:0 writeback:0
                             slab_reclaimable:5171 slab_unreclaimable:10557
                             mapped:2877 shmem:10220 pagetables:6130 bounce:0
                             free:14963 free_pcp:25 free_cma:0

在内核日志中看到发生异常是的内存具体指标数据

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
active_anon:4575kB    # 活跃的匿名内存(进程堆/栈等动态分配的内存)
inactive_anon:1652614kB # 不活跃的匿名内存(长期未使用的堆/栈)
isolated_anon:0kB     # 被隔离的匿名内存(通常为内存故障隔离
active_file:21kB      # 活跃的文件映射内存(如页缓存、打开的文件)
inactive_file:34kB    # 不活跃的文件映射内存
isolated_file:0kB     # 被隔离的文件映射内存
unevictable:1551kB    # 无法被交换或回收的内存(如 mlock 锁定的内存)
slab_reclaimable:5171kB  # 可回收的 Slab 缓存(如内核对象池)
slab_unreclaimable:10557kB # 不可回收的 Slab 缓存(如内核数据结构)
shmem:10220kB         # 共享内存(如 tmpfs、IPC 通信)
mapped:2877kB         # 文件映射内存(如共享库、内存映射文件)
pagetables:6130kB     # 进程虚拟地址到物理地址的映射表
free:14963kB          # 完全空闲的物理内存
free_pcp:25kB         # 每 CPU 空闲内存(用于本地分配)
free_cma:0kB          # CMA(连续内存分配器)空闲区

同时会输出对应的 NUMA 节点 0 的内存指标,可以看到几乎完全耗尽(尤其是匿名内存),且透明大页占用显著(anon_thp: 3829760kB),加剧了内存碎片化问题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[511 15:41:13 2025] Node 0 active_anon:18300kB inactive_anon:6610456kB active_file:76kB inactive_file:132kB unevictable:6204kB isolated(anon):0kB isolated(file):0kB mapped:11508kB dirty:0kB writeback:0kB shmem:40880kB shmem_thp: 0kB shmem_pmdmapped: 0kB anon_thp: 3829760kB writeback_tmp:0kB kernel_stack:6384kB all_unreclaimable? yes

使用 BPF 的方式

对于 BPF 的监控,主要通过 BPF 和 bpftrace 的 oomkill 工具,我们可以在触发 OOM killer 事件之后,观察到系统平均负载等一些其他的信息,原理是通过动态插桩内核函数 oom_kill_process(),捕获 OOM Killer 触发事件

比如平均负载信息可以在 OOM 发生时提供整个系统状态的一些 上下文信息,展示出系统整体是正在变忙还是处于稳定状态,以及那个进程触发了 OOM Killer 和,被 OOM Killer 杀掉的进程是那个等数据。

用内存测试工具简单复现一下 OOM killer,我们看看如何监控,这里需要把交换分区禁用掉,要不换页进程(kswapd)疯狂的输出,不太容易触发 OOM Killer

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@liruilongs.github.io ~]# swapoff -a  # 临时禁用

stress-ng 对 Linux 系统内存施加高压负载

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@liruilongs.github.io ~]# stress-ng --vm 4 --vm-bytes 9.5G  --timeout 60s
stress-ng: info:  [37336] setting to a 60 second run per stressor
stress-ng: info:  [37336] dispatching hogs: 4 vm
^[c^Cstress-ng: info:  [37336] successful run completed in 40.87s
[root@liruilongs.github.io ~]# 

通过 free 命令观察内存使用情况,中间的那一次输出可以直观的看到内存使用情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@liruilongs.github.io ~]# free -h -s 10  -c 3
               total        used        free      shared  buff/cache   available
Mem:           6.5Gi       815Mi       5.6Gi        37Mi       293Mi       5.7Gi
Swap:             0B          0B          0B

               total        used        free      shared  buff/cache   available
Mem:           6.5Gi       6.4Gi       183Mi        39Mi       113Mi       139Mi
Swap:             0B          0B          0B

               total        used        free      shared  buff/cache   available
Mem:           6.5Gi       4.5Gi       2.0Gi        39Mi        84Mi       2.0Gi
Swap:             0B          0B          0B
[root@liruilongs.github.io ~]# 

通过 oomkill 工具观察 OOM Killer 情况

内存分配失败调用栈,上面的 BPF 工具实际上是在 oom_kill_process 内核函数处埋点实现的

可以看到触发的进程主要是 stress-ng(内存压力测试工具)持续申请内存,导致系统物理内存耗尽。部分系统进程(如 oeaware、Xvnc)也触发 OOM,说明内存竞争激烈,系统整体处于高压状态。通过负载指标:loadavg 值较高(如 4.59),表明 CPU 资源负载在升高 。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@liruilongs.github.io ~]# /usr/share/bcc/tools/oomkill 
Tracing OOM kills... Ctrl-C to stop.
15:41:14 Triggered by PID 1039 ("oeaware"), OOM kill of PID 39693 ("stress-ng"), 1704429 pages, loadavg: 4.34 2.87 1.77 6/396 39695
15:41:15 Triggered by PID 39692 ("stress-ng"), OOM kill of PID 39692 ("stress-ng"), 1704429 pages, loadavg: 4.34 2.87 1.77 5/396 39696
15:41:16 Triggered by PID 39696 ("stress-ng"), OOM kill of PID 39694 ("stress-ng"), 1704429 pages, loadavg: 4.31 2.89 1.78 5/396 39697
15:41:17 Triggered by PID 39698 ("stress-ng"), OOM kill of PID 39695 ("stress-ng"), 1704429 pages, loadavg: 4.31 2.89 1.78 5/396 39699
15:41:19 Triggered by PID 1039 ("oeaware"), OOM kill of PID 39696 ("stress-ng"), 1704429 pages, loadavg: 4.31 2.89 1.78 5/396 39700
15:41:20 Triggered by PID 2121 ("ibus-ui-gtk3"), OOM kill of PID 39697 ("stress-ng"), 1704429 pages, loadavg: 4.31 2.89 1.78 6/396 39701
15:41:22 Triggered by PID 39699 ("stress-ng"), OOM kill of PID 39698 ("stress-ng"), 1704429 pages, loadavg: 4.29 2.91 1.80 5/396 39701
15:41:23 Triggered by PID 39700 ("stress-ng"), OOM kill of PID 39700 ("stress-ng"), 1704429 pages, loadavg: 4.29 2.91 1.80 6/396 39702
15:41:24 Triggered by PID 39701 ("stress-ng"), OOM kill of PID 39699 ("stress-ng"), 1704429 pages, loadavg: 4.29 2.91 1.80 5/396 39704
15:41:25 Triggered by PID 39702 ("stress-ng"), OOM kill of PID 39701 ("stress-ng"), 1704429 pages, loadavg: 4.29 2.91 1.80 5/396 39704
15:41:26 Triggered by PID 39703 ("stress-ng"), OOM kill of PID 39702 ("stress-ng"), 1704429 pages, loadavg: 4.59 3.00 1.83 5/396 39705
15:41:27 Triggered by PID 39705 ("stress-ng"), OOM kill of PID 39703 ("stress-ng"), 1704429 pages, loadavg: 4.59 3.00 1.83 5/396 39706
15:41:29 Triggered by PID 1304 ("Xvnc"), OOM kill of PID 39704 ("stress-ng"), 1704429 pages, loadavg: 4.59 3.00 1.83 6/396 39708
15:41:30 Triggered by PID 1492 ("lightdm-gtk-gre"), OOM kill of PID 39705 ("stress-ng"), 1704429 pages, loadavg: 4.59 3.00 1.83 5/395 39708
15:41:31 Triggered by PID 39709 ("stress-ng"), OOM kill of PID 39706 ("stress-ng"), 1704429 pages, loadavg: 4.94 3.10 1.87 8/395 39710

看下一下输出的指标信息,已第一条日志为例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
15:41:14 Triggered by PID 1039 ("oeaware"), OOM kill of PID 39693 ("stress-ng"), 1704429 pages, loadavg: 4.34 2.87 1.77 6/396 39695

字段

含义

Triggered by PID

触发 OOM 的进程 PID(如内存申请者)

OOM kill of PID

被 OOM Killer 终止的进程 PID

1704429 pages

被终止进程占用的物理内存页数(1页=4KB,换算为 6.8GB)

loadavg

系统负载(1分钟/5分钟/15分钟平均负载)

6/396

当前可运行进程数/总进程数

39695

最后被创建的进程 PID

当然上面的输出的功能有些简单,如果我们希望获取更多的数据信息,我们可以通过修改原来脚本的方式实现

bpftrace 对应的脚本

https://github.com/brendangregg/bpf-perf-tools-book/blob/master/originals/Ch07_Memory/oomkill.bt

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@liruilongs.github.io ~]# cat  /usr/share/bpftrace/tools/oomkill.bt 
#!/usr/bin/bpftrace
/*
 * oomkill Trace OOM killer.
 *  For Linux, uses bpftrace and eBPF.
 *
 * This traces the kernel out-of-memory killer, and prints basic details,
 * including the system load averages. This can provide more context on the
 * system state at the time of OOM: was it getting busier or steady, based
 * on the load averages? This tool may also be useful to customize for
 * investigations; for example, by adding other task_struct details at the
 * time of the OOM, or other commands in the system() call.
 *
 * This currently works by using kernel dynamic tracing of oom_kill_process().
 *
 * USAGE: oomkill.bt
 *
 * Copyright 2018 Netflix, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License")
 *
 * 07-Sep-2018 Brendan Gregg Created this.
 */

#include <linux/oom.h>

BEGIN
{
printf("Tracing oom_kill_process()... Hit Ctrl-C to end.\n");
}

kprobe:oom_kill_process
{
$oc = (struct oom_control *)arg0;
 time("%H:%M:%S ");
printf("Triggered by PID %d (\"%s\"), ", pid, comm);
printf("OOM kill of PID %d (\"%s\"), %d pages, loadavg: ",
     $oc->chosen->pid, $oc->chosen->comm, $oc->totalpages);
 cat("/proc/loadavg");
}
[root@liruilongs.github.io ~]# 

通过动态插桩内核函数 oom_kill_process(),捕获 OOM Killer 触发事件,同时输出了一些其他的指标信息

自定义 OOM Killer 发生时的性能指标采集

下面是最上面脚本的基础上添加的一些他的指标数据采集,从而实现在 OOM Killer 发生时快速的定位问题

添加 /proc/meminfo 的全局内存指标信息,meminfo提供了系统范围内内存统计数据的超集,包括了vmstat、top、free和procinfo的信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <linux/oom.h>

BEGIN
{
        printf("Tracing oom_kill_process()... Hit Ctrl-C to end.\n");
}

kprobe:oom_kill_process
{
        $oc = (struct oom_control *)arg0;
        $task = $oc->chosen;
        time("%H:%M:%S ");
        printf("Triggered by PID %d (\"%s\"), ", pid, comm);
        printf("OOM kill of PID %d (\"%s\"), %d pages, loadavg: ",
            $oc->chosen->pid, $oc->chosen->comm, $oc->totalpages);
        cat("/proc/loadavg");
        print("当前系统内存性能统计信息:");
        cat("/proc/meminfo");
}

修改脚本后的再次监控指标采集

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@developer tools]# vim oomkill.bt
[root@developer tools]# ./oomkill.bt
Attaching 2 probes...
Tracing oom_kill_process()... Hit Ctrl-C to end.
19:06:46 Triggered by PID 1039 ("oeaware"), OOM kill of PID 1528049 ("stress-ng"), 1704429 pages, loadavg: 4.14 2.26 1.35 5/405 1528051
当前系统内存性能统计信息:
MemTotal:        6817716 kB
MemFree:         1494936 kB
MemAvailable:    1442388 kB
Buffers:             372 kB
Cached:           155720 kB
SwapCached:            0 kB
Active:            31476 kB
Inactive:        5156300 kB
Active(anon):      31388 kB
Inactive(anon):  5117004 kB
Active(file):         88 kB
Inactive(file):    39296 kB
Unevictable:        6236 kB
Mlocked:              76 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:       5038288 kB
Mapped:            21148 kB
Shmem:            116328 kB
KReclaimable:      21692 kB
Slab:              66816 kB
SReclaimable:      21692 kB
SUnreclaim:        45124 kB
KernelStack:        6528 kB
PageTables:        22160 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     3408856 kB
Committed_AS:   12252200 kB
VmallocTotal:   135290159040 kB
VmallocUsed:       16152 kB
VmallocChunk:          0 kB
Percpu:             2800 kB
HardwareCorrupted:     0 kB
AnonHugePages:   4009984 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB

对于内核态的内存分配,可以添加 /proc/slabinfo 相关指标的采集

上面是全局的内存信息的指标采集,当然也可以采集对被 kill 进程以及 创建的进程的相关的指标信息

下面的为提供的 BCC 版本的 oomkill 工具

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@liruilongs.github.io ~]# cat /usr/share/bcc/tools/oomkill 
#!/usr/bin/python3
#
# oomkill   Trace oom_kill_process(). For Linux, uses BCC, eBPF.
#
# This traces the kernel out-of-memory killer, and prints basic details,
# including the system load averages. This can provide more context on the
# system state at the time of OOM: was it getting busier or steady, based
# on the load averages? This tool may also be useful to customize for
# investigations; for example, by adding other task_struct details at the time
# of OOM.
#
# Copyright 2016 Netflix, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
#
# 09-Feb-2016   Brendan Gregg   Created this.

from bpfcc import BPF
from time import strftime

# linux stats
loadavg = "/proc/loadavg"

# define BPF program
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/oom.h>

struct data_t {
    u32 fpid;
    u32 tpid;
    u64 pages;
    char fcomm[TASK_COMM_LEN];
    char tcomm[TASK_COMM_LEN];
};

BPF_PERF_OUTPUT(events);

void kprobe__oom_kill_process(struct pt_regs *ctx, struct oom_control *oc, const char *message)
{
    unsigned long totalpages;
    struct task_struct *p = oc->chosen;
    struct data_t data = {};
    u32 pid = bpf_get_current_pid_tgid() >> 32;
    data.fpid = pid;
    data.tpid = p->pid;
    data.pages = oc->totalpages;
    bpf_get_current_comm(&data.fcomm, sizeof(data.fcomm));
    bpf_probe_read_kernel(&data.tcomm, sizeof(data.tcomm), p->comm);
    events.perf_submit(ctx, &data, sizeof(data));
}
"""

# process event
def print_event(cpu, data, size):
    event = b["events"].event(data)
    with open(loadavg) as stats:
        avgline = stats.read().rstrip()
    print(("%s Triggered by PID %d (\"%s\"), OOM kill of PID %d (\"%s\")"
        ", %d pages, loadavg: %s") % (strftime("%H:%M:%S"), event.fpid,
        event.fcomm.decode('utf-8', 'replace'), event.tpid,
        event.tcomm.decode('utf-8', 'replace'), event.pages, avgline))

# initialize BPF
b = BPF(text=bpf_text)
print("Tracing OOM kills... Ctrl-C to stop.")
b["events"].open_perf_buffer(print_event)
while1:
    try:
        b.perf_buffer_poll()
    except KeyboardInterrupt:
        exit()
[root@liruilongs.github.io ~]# 

我们对这个工具做一些简单的修改, /proc/pid/status 用于展示当前进程的一些基本指标

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# process event
def print_event(cpu, data, size):
    event = b["events"].event(data)
    with open(loadavg) as stats:
        avgline = stats.read().rstrip()
    with open("/proc/"+ str(event.fpid) +"/status" ) as statm:
        statmtable = statm.read().rstrip()
    print(("%s Triggered by PID %d (\"%s\"), OOM kill of PID %d (\"%s\")"
        ", %d pages, loadavg: %s") % (strftime("%H:%M:%S"), event.fpid,
        event.fcomm.decode('utf-8', 'replace'), event.tpid,
        event.tcomm.decode('utf-8', 'replace'), event.pages, avgline))
    print("新进程指标信息: &s",statmtable)

下面为输出结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@developer tools]# ./oomkill
Tracing OOM kills... Ctrl-C to stop.
19:42:24 Triggered by PID 1539774 ("stress-ng"), OOM kill of PID 1539775 ("stress-ng"), 1704429 pages, loadavg: 2.40 1.72 1.07 5/407 1539778
新进程指标信息: &s Name: stress-ng
Umask: 0077
State: R (running)
Tgid: 1539774
Ngid: 0
Pid: 1539774
PPid: 1539770
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 64
Groups: 0 
NStgid: 1539774
NSpid: 1539774
NSpgid: 1539769
NSsid: 32074
VmPeak:  2410404 kB
VmSize:  2410404 kB
VmLck:        0 kB
VmPin:        0 kB
VmHWM:  1415824 kB
VmRSS:  1415824 kB
RssAnon:  1415760 kB
RssFile:        4 kB
RssShmem:       60 kB
VmData:  2369388 kB
VmStk:      132 kB
VmExe:     1416 kB
VmLib:     2888 kB
VmPTE:     2828 kB
VmSwap:        0 kB
HugetlbPages:        0 kB
CoreDumping: 0
THP_enabled: 1
Threads: 1
SigQ: 0/26524
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000008300a00
SigCgt: 000000002380e0af
CapInh: 0000000000000000
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Seccomp_filters: 0
Speculation_Store_Bypass: vulnerable
Cpus_allowed: f
Cpus_allowed_list: 0-3
Mems_allowed: 00000000,00000000,00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 32
nonvoluntary_ctxt_switches: 837
Cpus_preferred: 0
Cpus_preferred_list:

我们可以同时采集到 VmRSS 等有用的指标信息。

BPF 跟踪工具可以给各种内存行为提供更多的信息,可以用 BPF 跟踪软件事件系统调用缺页错误相关的跟踪点来分析;还可以使用 kprobes 跟踪内核中内存分配的函数;或使用 uprobes 来跟踪库函数、应用程序运行时,以及应用程序自带的内存分配器;或使用 USDT 探针来跟踪 libc 内存分配器事件;以及使用 PMC对内存访问进行溢出采样。感兴趣的小伙伴可以深入了解。

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)


《BPF Performance Tools》


© 2018-至今 liruilonger@gmail.com, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 山河已无恙 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深入了解Linux OOM Killer:一次可怕的内核事件
The OOM Killer 是内核中的一个进程,当系统出现严重内存不足时,它就会启用自己的算法去选择某一个进程并杀掉. 之所以会发生这种情况,是因为Linux内核在给某个进程分配内存时,会比进程申请的内存多分配一些. 这是为了保证进程在真正使用的时候有足够的内存,因为进程在申请内存后并不一定立即使用,当真正使用的时候,可能部分内存已经被回收了。
嵌入式Linux内核
2023/08/08
5.9K0
深入了解Linux OOM Killer:一次可怕的内核事件
Kubernetes中资源限制的一些笔记整理
我们的痛苦来源于“夸父追日”一般的对“更好”的追求,也来自于自己的自卑与狂妄。--------duoduokk
山河已无恙
2023/01/30
6150
记一次CentOS OOM内存溢出案例
业务进程异常停止或重启,可以根据 /var/log/messages 日志判断是否发生OOM,如果是,又是什么进程占用了大量内存空间触发 OOM Killer
大大大黑白格子
2020/07/06
4.1K0
内核参数导致的备库宕机分析 (一)r7笔记第23天
在前几天搭建好备库之后,因为同步文件着实花了些时间,首先配置备库能够正常接收归档,然后内核参数也基本没有设置,简单使用脚本算出一个 Hugepage的值,就直接改了。当时从数据库日志中确实也没有发现hugepage启用的情况,但是因为不是很影响备库的性能,自己就没有重视。 结果早上的时候,首先受到了一封报警邮件。 ZABBIX-监控系统: ------------------------------------ 报警内容: DG_issue -----------------------------
jeanron100
2018/03/16
1.5K0
linux out of memory分析(OOM)
原文:http://blog.csdn.net/guomsh/article/details/6536915
一见
2019/03/14
9K0
MySQL OOM(内存溢出)的排查思路及优化方法
大部分情况下,会杀掉导致OOM的进程,然后系统恢复。通常我们会添加对内存的监控报警,例如:当memory或swap使用超过90%时,触发报警通知,需要及时介入排查。
MySQL轻松学
2019/08/01
10K0
Linux性能调优之内存负载调优的一些笔记
「 原谅和忘记就意味着扔掉了我们获得的最贵经验 -------《人生的智慧》叔本华」
山河已无恙
2023/01/30
2.7K0
Linux性能调优之内存负载调优的一些笔记
Kubernetes 内存资源限制实战
Kubernetes 对内存资源的限制实际上是通过 cgroup 来控制的,cgroup 是容器的一组用来控制内核如何运行进程的相关属性集合。针对内存、CPU 和各种设备都有对应的 cgroup。cgroup 是具有层级的,这意味着每个 cgroup 拥有一个它可以继承属性的父亲,往上一直直到系统启动时创建的 root cgroup。关于其背后的原理可以参考:深入理解Kubernetes资源限制:内存。
米开朗基杨
2019/08/29
3.2K0
Kubernetes 内存资源限制实战
centos7 cgroup oom触发访问ext4文件系统卡死
centos7 3.10.0-1160.62.1.el7.x86_64内核版本已修复该问题,CentOS7受影响内核版本 3.10.0-862.el7 - 3.10.0-1160.59.1.el7
cdh
2022/04/15
2.9K3
高性能:8-可用于Memory分析的BPF工具【bpf performance tools读书笔记】
内核和处理器负责将虚拟内存映射到物理内存。为了提高效率,会在称为页面的内存组中创建内存映射,其中每个页面的大小是处理器的详细信息。尽管大多数处理器也支持更大的容量,但通常有4 KB,Linux称其为 hugepage大页面。内核可以从其自己的空闲列表中为物理内存页面请求提供服务,内核为每个DRAM组和CPU维护这些请求以提高效率。内核自己的软件也通常通过内核分配器(例如slab分配器)从这些空闲列表中消耗内存。
保持热爱奔赴山海
2020/03/06
2.7K0
高性能:8-可用于Memory分析的BPF工具【bpf performance tools读书笔记】
关于 Linux中系统调优的一些笔记
我突然又明白,死亡是聪明的兄长,我们可以放心地把自己托付给他,他会知道在我们有所准备的适当时刻前来。我也突然懂得,原来痛苦、失望和悲愁不是为了惹恼我们,使我们气馁或者无地自容;它们的存在,是为了使我们心智成熟,臻于完善。—赫尔曼·黑塞《彼得·卡门青》
山河已无恙
2023/03/02
1K0
关于 Linux中系统调优的一些笔记
Linux 进程内存监控:Linux 内存调优之进程内存深度监控
这里分析的工具主要是原生工具,后面还会分享一些 BPF 相关的内存观察工具以及系统内存的全局监控
山河已无恙
2025/04/13
9060
Linux 进程内存监控:Linux 内存调优之进程内存深度监控
Kubernetes 触发 OOMKilled(内存杀手)如何排除故障 | 技术创作特训营第一期
对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大众理想的懦弱回归,是随波逐流,是对内心的恐惧 ——赫尔曼·黑塞《德米安》
山河已无恙
2023/08/11
4.7K0
Linux内核参数min_free_kbytes与lowmem_reserve_ratio
解释已经很清楚了,主要有以下几个关键点: 1. 1 代表系统所保留空闲内存的最低限
Linux阅码场
2020/03/20
2.5K0
Linux 系统内存监控:Linux 内存调优之系统内存全面监控
所谓百年功名、千秋霸业、万古流芳,与一件事情相比,其实算不了什么。这件事情就是——用你喜欢的方式度过一生。 ----《明朝那些事儿》
山河已无恙
2025/04/13
4110
Linux 系统内存监控:Linux 内存调优之系统内存全面监控
关于Linux性能调优中系统CPU监测信息统计的一些笔记
人总是害怕去追求自己最重要的梦想,因为他们觉得自己不配拥有,或者觉得自己没有能力去完成。——保罗.柯艾略《牧羊少年奇幻之旅》
山河已无恙
2023/03/02
9220
关于Linux性能调优中系统CPU监测信息统计的一些笔记
【调试】sysRq键使用方法
SysRq键是一个魔术案件,只要在内核没有完全卡死的情况下,内核都会相应SysRq 键的输入,使用这些组合键都可以搜集包括系统内存使用、CPU任务处理、进程运行状态等系统运行信息。
嵌入式与Linux那些事
2023/02/13
8520
【调试】sysRq键使用方法
linux下python程序KILLED记录
本来,写了个智能抠图的接口,本地运行正常,结果部署到服务器,发现,各种失败或服务器错误,查看log日志发现是本kill了
一朵灼灼华
2022/08/05
1.7K0
linux下python程序KILLED记录
kubernetes中不可见的OOM
最近看了一篇文章:Tracking Down “Invisible” OOM Kills in Kubernetes,其讲述的是由于内存不足导致Pod中的进程被killed,但Pod并没有重启,也没有任何日志或kubernetes事件,只有一个"Exit Code: 137"的信息,导致难以进一步定位问题。最后还是通过查看节点系统日志才发现如下信息:
charlieroro
2022/09/21
1.4K0
oom killer
Linux系统内存管理中存在着一个称之为OOM killer(Out-Of-Memory killer)的机制,该机制主要用于内存监控,监控进程的内存使用量,当系统的内存耗尽时,其将根据算法选择性地kill了部分进程。本文分析的内存溢出保护机制,也就是OOM killer机制了。
233333
2019/05/25
2K0
相关推荐
深入了解Linux OOM Killer:一次可怕的内核事件
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验