[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81930":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":13,"contributorsCount":13,"subscribersCount":13,"size":13,"stars1d":13,"stars7d":15,"stars30d":16,"stars90d":13,"forks30d":13,"starsTrendScore":13,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":18,"hasPages":18,"topics":20,"createdAt":10,"pushedAt":10,"updatedAt":21,"readmeContent":22,"aiSummary":23,"trendingCount":13,"starSnapshotCount":13,"syncStatus":24,"lastSyncTime":25,"discoverSource":26},81930,"MemSnoop-An-eBPF-Memory-Analysis-Engine-with-CO-RE-Support","kkst1\u002FMemSnoop-An-eBPF-Memory-Analysis-Engine-with-CO-RE-Support","kkst1","MemSnoop — eBPF-based kernel memory tracing tool. Real-time kmalloc\u002Fkfree monitoring with per-process stats, allocation histograms, call stack hotspot analysis, and kernel symbol resolution.","",null,"C",35,0,25,1,10,38.5,false,"master",[],"2026-06-12 04:01:36","# MemSnoop - eBPF Memory Analysis Engine\n\n基于 eBPF 的内核内存分配追踪与分析工具。实时监控 `kmalloc`\u002F`kfree`，提供进程级统计、分配大小分布直方图、调用栈热点分析、内核符号解析和疑似泄漏检测。\n\n## 环境要求\n\n| 组件 | 最低版本 |\n|------|---------|\n| Linux Kernel | 5.8+ (需要 BTF 和 ring buffer 支持) |\n| clang\u002Fllvm | 12+ |\n| bpftool | 5.12+ |\n| libbpf | 0.6+ (CO-RE 支持) |\n| libelf, zlib | 发行版默认版本 |\n\n验证内核是否支持 BTF：\n\n```bash\nls \u002Fsys\u002Fkernel\u002Fbtf\u002Fvmlinux   # 文件存在即可\n```\n\n## 构建\n\n```bash\nmake            # 生成 vmlinux.h → 编译 BPF → 生成 skeleton → 编译用户态\nmake vmlinux    # 重新生成 vmlinux.h（换内核后需要）\nmake clean      # 清除构建产物\n```\n\n构建流程：\n1. `bpftool btf dump` 从运行内核提取 `vmlinux.h`\n2. `clang -target bpf` 编译 BPF 程序\n3. `bpftool gen skeleton` 生成 BPF skeleton 头文件\n4. `gcc` 编译用户态程序，链接 `libbpf`、`libelf`、`libz`\n\n## 运行\n\n```bash\nsudo .\u002Foutput\u002Fmemsnoop [OPTIONS]\n# 或使用自动提权脚本\nsudo .\u002Fscripts\u002Frun.sh [OPTIONS]\n```\n\n## 命令行选项\n\n| 选项 | 说明 | 默认值 |\n|------|------|--------|\n| `--pid \u003Cpid>` | 只追踪指定进程 | 追踪全部 |\n| `--top \u003Cn>` | 显示 Top N 进程 | 10 |\n| `--interval \u003Csec>` | 报告刷新间隔 | 1 秒 |\n| `--duration \u003Csec>` | 运行指定秒数后退出 | 0 (持续运行) |\n| `--hist` | 显示分配大小直方图 | 关闭 |\n| `--stack` | 显示分配热点调用栈 | 关闭 |\n| `--leak-after \u003Csec>` | 报告存活超过指定秒数的分配 | 0 (不启用) |\n| `--min-size \u003Cbytes>` | 只报告大于指定大小的分配 (支持 K\u002FM\u002FG) | 0 (不过滤) |\n| `--verbose` | 逐条打印每个事件 | 关闭 |\n| `--help` | 显示帮助信息 | - |\n\n## 架构\n\n```\n┌─────────────────────────────────────────────────────┐\n│                    用户态 (user\u002F)                     │\n│  main.c ─ skeleton 加载\u002Fattach ─ ring buffer poll    │\n│  stats.c ─ PID统计 \u002F 直方图 \u002F 栈热点显示              │\n│  syms.c  ─ \u002Fproc\u002Fkallsyms 符号解析                   │\n└───────────────────┬─────────────────────────────────┘\n                    │ ring buffer (4MB)\n┌───────────────────┴─────────────────────────────────┐\n│                  内核态 (bpf\u002Fmem.bpf.c)               │\n│  tracepoint\u002Fkmem\u002Fkmalloc  → alloc_table + ring buf   │\n│  tracepoint\u002Fkmem\u002Fkfree    → alloc_table + ring buf   │\n│  7 个 BPF Map: events, stack_traces, pid_stats_map,  │\n│    alloc_table, hist_map, target_pid, stats           │\n└─────────────────────────────────────────────────────┘\n```\n\n### 为什么选择 Ring Buffer\n\n- **低开销**：单个共享缓冲区，无需 per-CPU 分配\n- **事件有序**：同一 ring buffer 内事件保持时间顺序\n- **libbpf 原生支持**：`ring_buffer__new()` \u002F `ring_buffer__poll()` API 简洁\n- **适合高频事件**：内存分配\u002F释放是极高频操作，ring buffer 的批量提交机制能有效应对\n\n### BPF Maps\n\n| Map | 类型 | 用途 |\n|-----|------|------|\n| `events` | RINGBUF | 事件传输出口 |\n| `stack_traces` | STACK_TRACE | 存储内核栈帧 |\n| `pid_stats_map` | HASH | 每进程 alloc\u002Ffree 统计 |\n| `alloc_table` | HASH | 追踪未释放的分配 |\n| `hist_map` | PERCPU_ARRAY | 分配大小直方图 |\n| `target_pid` | ARRAY | PID 过滤器 |\n| `stats` | ARRAY | 全局计数器 (total\u002Fdropped) |\n\n## 分配大小直方图\n\n使用 `--hist` 开启，将分配按大小分为 8 个区间：\n\n```\nSIZE_RANGE     COUNT      DISTRIBUTION\n0-64B          12345      |################################\n64-256B        8900       |#######################\n256B-1KB       3400       |#########\n1KB-4KB        1200       |###\n4KB-16KB       450        |#\n16KB-64KB      120        |\n64KB-256KB     30         |\n256KB+         5          |\n```\n\n直方图帮助判断内存行为模式：\n- **小对象密集** (0-64B 占比高)：常见于 slab 分配器、内核对象缓存\n- **大对象频繁** (4KB+ 占比高)：可能存在 buffer 分配策略问题\n- **分布均匀**：典型的混合工作负载\n\n## 调用栈热点分析\n\n使用 `--stack` 开启。通过 `BPF_MAP_TYPE_STACK_TRACE` 采集内核栈帧，以栈 ID 为 key 聚合分配字节数和次数，输出 TopN 热点。\n\n```\n#1  stack_id=42     1.2MB (3500 allocs)\n       [0] __kmalloc+0x4a (0xffffffff81234567)\n       [1] ext4_alloc_inode+0x28 (0xffffffff81abcdef)\n       [2] alloc_inode+0x5c (0xffffffff81345678)\n```\n\n### 符号解析\n\n程序启动时从 `\u002Fproc\u002Fkallsyms` 加载内核符号表，使用二分查找将栈地址解析为函数名+偏移。\n\n**依赖与限制：**\n- 需要 `\u002Fproc\u002Fkallsyms` 可读（通常需要 root 权限）\n- `kptr_restrict=1`：kallsyms 中所有地址为 0，程序会检测并警告，回退显示原始地址\n  - 修复：`echo 0 | sudo tee \u002Fproc\u002Fsys\u002Fkernel\u002Fkptr_restrict`\n- `kptr_restrict=2`：kallsyms 不可读，同样回退到原始地址\n- KASLR 不影响解析：kallsyms 中的虚拟地址与内核栈地址在同一地址空间\n- 模块符号不显示 `[module]` 后缀\n\n### Verifier 限制说明\n\neBPF verifier 对程序复杂度有限制。本项目的策略是：\n- **eBPF 侧只采集轻量数据**：地址、大小、栈 ID\n- **复杂聚合放在用户态**：PID 排序、栈热点聚合、符号解析都在用户态完成\n\n## 疑似泄漏检测\n\n使用 `--leak-after \u003Csec>` 开启。扫描 `alloc_table` 中存活超过指定秒数的未释放分配，按大小降序输出 TopN。\n\n```bash\n# 检测存活超过 5 秒的未释放分配\nsudo .\u002Foutput\u002Fmemsnoop --leak-after 5 --stack --interval 3 --duration 10\n\n# 只关注大于 1KB 的疑似泄漏\nsudo .\u002Foutput\u002Fmemsnoop --leak-after 3 --min-size 1K --stack\n```\n\n输出示例：\n```\n  [Suspected Leaks (age > 5s, size >= 64B)]\n\n  PID       SIZE          AGE     STACK_ID\n  1234      16.0KB        8s      42\n       [0] __kmalloc+0x290 (0xffffffffac06b2d0)\n       [1] vmw_view_add+0xa3 (0xffffffffc076f2e3)\n  Total suspected leaks: 1\n```\n\n**重要说明**：这是\"疑似泄漏检测\"，不是内核级 `kmemleak` 的替代品。它只能发现\"分配了但没释放\"的对象，无法判断：\n- 是否是有意的长生命周期分配\n- 是否存在对数据结构的引用\n- 真正的泄漏确认需要内核级 kmemleak（使用垃圾回收扫描）\n\n### 泄漏测试\n\n编译并运行测试程序，故意制造未释放分配：\n\n```bash\nmake\n.\u002Foutput\u002Fleak_test &          # 后台运行，分配 5 块不释放\nsudo .\u002Foutput\u002Fmemsnoop --leak-after 3 --min-size 64 --stack --interval 2 --duration 8\n```\n\n## 压力测试\n\n```bash\n.\u002Fscripts\u002Fstress_alloc.sh [duration_sec]\n```\n\n生成 4 种分配模式：\n1. 小对象频繁分配 (dd 512B)\n2. 大块分配 (dd 64KB)\n3. 快速创建\u002F删除 (alloc+free 高频交替)\n4. 网络 socket 分配 (curl)\n\n## 项目结构\n\n```\nmemsnoop\u002F\n├── bpf\u002Fmem.bpf.c              # 内核态 BPF 程序\n├── include\u002Fmem_common.h        # BPF 与用户态共享的数据结构\n├── user\u002F\n│   ├── main.c                  # 入口、CLI、事件循环\n│   ├── stats.c                 # 统计显示 (PID\u002F直方图\u002F栈\u002F泄漏)\n│   ├── syms.c                  # 内核符号解析\n│   ├── mem.skel.h              # 自动生成的 BPF skeleton\n│   └── include\u002F\n│       ├── mem_user.h          # CLI 解析、格式化工具\n│       ├── stats.h             # 统计显示接口\n│       └── syms.h              # 符号解析接口\n├── scripts\u002F\n│   ├── run.sh                  # 运行脚本 (自动 sudo)\n│   ├── stress_alloc.sh         # 压力测试脚本\n│   └── leak_test.c             # 泄漏测试程序\n├── docs\u002F\n│   ├── architecture.md         # 架构文档、设计取舍\n│   └── interview-notes.md      # 面试笔记、技术问答\n├── Makefile\n└── README.md\n```\n\n## 限制\n\n- 需要 root 权限（eBPF 需要 CAP_BPF + CAP_PERFMON）\n- 需要内核支持 BTF（`\u002Fsys\u002Fkernel\u002Fbtf\u002Fvmlinux` 存在）\n- libbpf 版本需要 >= 1.4（Ubuntu 22.04 默认 0.5.0 太旧）\n- 只追踪 `kmalloc`\u002F`kfree`，不覆盖 `vmalloc`、`page_alloc` 等\n- 泄漏检测是\"疑似\"级别，不替代内核 kmemleak\n- `alloc_table` 最多追踪 65536 个未释放分配\n","MemSnoop 是一个基于 eBPF 的内核内存分配追踪与分析工具，能够实时监控 `kmalloc` 和 `kfree` 操作，并提供详细的进程级统计、分配大小分布直方图、调用栈热点分析和内核符号解析等功能。该工具利用了 eBPF 技术的高效性和灵活性，支持 CO-RE（Compile Once - Run Everywhere），确保在不同内核版本上的一致性表现。特别适合于需要深入理解或优化系统内存使用情况的场景，如性能调试、内存泄漏检测以及安全审计等。通过丰富的命令行选项，用户可以灵活配置监测范围和报告格式，从而更好地满足特定需求。",2,"2026-06-11 04:07:14","CREATED_QUERY"]