关于 kernel-internals
kernel-internals 是面向 Agent 的 Linux 内核内部知识技能,涵盖调度、内存管理、VFS、页缓存和 OOM。它将子系统概念与诊断命令及常见排查路径结合。
主要功能
- 01CFS 与 EEVDF 调度原理
- 02伙伴分配器与 SLUB 分析
- 03kmalloc 与 vmalloc 用法
- 04VFS 与页缓存机制
- 05/proc/meminfo 与 OOM 诊断
适用场景
- 01排查调度延迟或 CPU 分配不均
- 02分析内核内存分配失败
- 03检查页缓存与预读行为
- 04诊断内存压力和 OOM 选择
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill kernel-internals安装后在 Claude Code 中输入/kernel-internals确认已加载。
详细介绍
内核内部机制
用途
指导 Agent 了解 Linux 内核内部机制:CFS 和 EEVDF 调度器、运行队列和 vruntime、伙伴分配器和 SLUB、vmalloc 与 kmalloc、VFS dentry/inode/file 对象、页缓存和预读、内存区域、OOM killer 启发式算法,以及 /proc/meminfo 解读。
适用场景
- 诊断调度延迟或 CPU 分配不公平
- 了解大型内核分配中 kmalloc 失败与 vmalloc 的区别
- 分析页缓存行为和预读效果
- 在内存压力期间解读
/proc/meminfo - 调试 OOM killer 的受害进程选择
- 阅读
kernel/sched/、mm/或fs/中的内核源码
工作流
1. 调度器 — CFS 和 EEVDF
Linux 对 CFS 类调度使用 EEVDF(最早合格虚拟截止时间优先)。EEVDF 于 6.6(2023)作为一个选项合入;CFS→EEVDF 的逐步迁移已于 6.12(2024 年 11 月)完成。对于较旧的 6.6–6.11 内核,请确认当前启用的是哪个调度器。核心概念(运行队列、vruntime/lag)仍然适用:
Per-CPU runqueue (struct rq)
├── cfs_rq — fair-class tasks sorted by vruntime/deadline
├── rt_rq — real-time tasks (FIFO/RR)
└── dl_rq — SCHED_DEADLINE tasks
关键指标:
# Task scheduling info
chrt -p <pid>
cat /proc/<pid>/sched
# Runqueue latency (scheduler debugging)
cat /sys/kernel/debug/sched/debug # requires debugfs
# Trace scheduler events
perf sched record -a -- sleep 5
perf sched latency
vruntime — 跟踪已消耗 CPU 时间的虚拟运行时间;vruntime 越低,越有资格获得 CPU。
# CFS tunables
sysctl kernel.sched_latency_ns
sysctl kernel.sched_min_granularity_ns
sysctl kernel.sched_wakeup_granularity_ns
2. EEVDF 具体机制
EEVDF 会选择合格任务中虚拟截止时间最早的任务,从而改善短时间片任务的延迟公平性。lag 为正的任务符合资格;调度器会在符合资格的任务中选择虚拟截止时间最早的任务。
# Check kernel version (EEVDF transition complete in 6.12+)
uname -r
# Scheduler documentation
# docs.kernel.org/scheduler/sched-eevdf.html
3. 内存子系统 — 伙伴分配器
物理页按 2 的幂次序分配(order 0 = 4KB,order 1 = 8KB,……)。
ZONE_DMA / ZONE_DMA32 / ZONE_NORMAL / ZONE_MOVABLE
└── free_area[MAX_ORDER] — buddy lists per order
# Buddy allocator stats
cat /proc/buddyinfo
# Per-zone page counts
cat /proc/zoneinfo | head -80
4. SLUB 分配器
默认的 kmalloc 后端——为常用大小维护每 CPU 缓存(slab)。
# SLUB debug (requires CONFIG_SLUB_DEBUG)
cat /sys/kernel/slab/*/objects 2>/dev/null | head
# kmalloc size classes visible in /proc/slabinfo
cat /proc/slabinfo | head -20
| API | 适用场景 |
|---|---|
kmalloc(size, GFP_KERNEL) | ≤ ~128KB(取决于架构),物理连续 |
kzalloc(size, flags) | 清零的 kmalloc |
vmalloc(size) | 大块、虚拟连续(物理上可能不连续) |
get_free_pages() | 直接分配页面 |
// Kernel module allocation example
void *buf = kmalloc(4096, GFP_KERNEL);
if (!buf)
return -ENOMEM;
kfree(buf);
5. 高端内存
在 32 位系统或特定配置中,ZONE_HIGHMEM 保存未永久映射到内核虚拟地址空间的页面。在 64 位 x86/arm64 上,几乎所有 RAM 都位于 ZONE_NORMAL。
grep -i highmem /proc/zoneinfo
6. VFS 层
Path lookup: /home/user/file.txt
├── dentry cache (dcache) — directory entry tree
├── inode — metadata (permissions, size, ops)
└── file — per-open-file state (offset, flags)
# Mounted filesystems
cat /proc/mounts
# Inode/dentry cache pressure
sysctl vm.vfs_cache_pressure # higher = reclaim caches sooner
# File descriptor usage
ls /proc/<pid>/fd | wc -l
7. 页缓存和预读
# Drop caches (testing only — destructive to perf)
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
# Readahead tuning
blockdev --getra /dev/sda
blockdev --setra 4096 /dev/sda
# Per-file cache status
cat /proc/<pid>/smaps_rollup
页缓存页面会显示在 meminfo 的 Cached 中。脏页会等待回写。
8. 解读 /proc/meminfo
cat /proc/meminfo
| 字段 | 含义 |
|---|---|
MemTotal | 可用 RAM 总量 |
MemFree | 完全未使用的页面 |
MemAvailable | 可分配内存的估算值(包括可回收缓存) |
Cached | 页缓存 + tmpfs |
Buffers | 块设备元数据缓存 |
SwapTotal / SwapFree | 交换空间 |
Dirty | 等待回写的页面 |
AnonPages | 匿名(堆/栈)页面 |
Slab | 内核对象缓存 |
SReclaimable | 可回收的 slab |
SUnreclaim | 内核结构(不易回收) |
Memory pressure diagnosis
├── MemAvailable low + Cached high → page cache reclaim candidate
├── AnonPages high + SwapFree low → OOM risk
├── Slab huge → kernel object leak; check /proc/slabinfo
└── Dirty high → slow writeback; check I/O scheduler
9. OOM killer
# OOM score per process (higher = more likely victim)
cat /proc/<pid>/oom_score
cat /proc/<pid>/oom_score_adj # -1000 to 1000, admin adjustment
# OOM events in kernel log
dmesg | grep -i "out of memory"
journalctl -k | grep -i oom
OOM killer 会根据 oom_score 进行选择,并考虑内存用量、子进程和 oom_score_adj。保护关键守护进程:
# Protect process from OOM (requires root)
echo -1000 | sudo tee /proc/<pid>/oom_score_adj
常见问题
| 症状 | 原因 | 修复方法 |
|---|---|---|
kmalloc: allocation failed | 内存碎片化或分配大小过大 | 使用 vmalloc;降低内存压力;仅在需要时使用 GFP_ATOMIC |
| iowait 高,MemAvailable 低 | 页缓存抖动 | 增加 RAM;调整 vfs_cache_pressure |
| OOM 杀死了错误的进程 | 内存用量高但 adj 值低 | 设置 oom_score_adj;使用 cgroups memory.max |
| 调度不公平 | RT 任务导致 CFS 饥饿 | 检查 chrt;使用 isolcpus 隔离 CPU |
| SLUB 损坏 | 模块中存在释放后使用问题 | 启用 KASAN;使用 slub_debug 进行审查 |
| 文件读取缓慢 | 预读量过小 | 增加预读量;检查后端设备 |
相关技能
skills/kernel/device-drivers— 使用这些子系统的字符设备/平台驱动skills/kernel/kernel-debugging— 使用 ftrace、kgdb 调查内核内部skills/low-level-programming/linux-kernel-modules— LKM 开发基础skills/kernel/kernel-testing— 使用 KUnit 编写子系统单元测试skills/profilers/linux-perf— 使用 perf sched 进行性能和内存分析skills/observability/ebpf— 从用户空间跟踪调度器和内存事件