环境
map 定义:
scss
#define PERF_MAX_STACK_DEPTH 128
struct
{
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
__uint(key_size, sizeof(u32));
__uint(value_size, PERF_MAX_STACK_DEPTH * sizeof(u64));
__uint(max_entries, 10000);
} stack_traces SEC(".maps");
启动报错:
bash
2025-06-11T14:29:58.761+0800 FATAL memleak/main.go:69 加载 BPF 程序失败 {"error": "load and attach BPF programs failed: load collection error: map stack_traces: map create: invalid argument"}
main.main
/workload/BeePF/example/memleak/main.go:69
runtime.main
/workload/go/pkg/mod/golang.org/[email protected]/src/runtime/proc.go:272
make: *** [Makefile:33: run] Error 1
排查
命令:retsnoop -e '*sys_bpf' -TAS -C args.fmt-mode=verbose
日志:
ini
14:29:58.761884 -> 14:29:58.761888 TID/PID 60628/60626 (memleak/memleak):
FUNCTION CALLS RESULT DURATION
--------------- --------- --------
→ __x64_sys_bpf
› __unused = &{
.r15 = 0xffffffff,
.r14 = 0xc0000061c0,
.r13 = 0xc0016ddf80,
.r12 = 0xc0016d40f0,
.bp = 0xc0016d3f70,
.r11 = 534,
.ax = 0xffffffffffffffda,
.cx = 0x4808ee,
.dx = 80,
.si = 0xc0016d4360,
.orig_ax = 321,
.ip = 0x4808ee,
{
.cs = 51,
.csx = 51,
.fred_cs = {
.cs = 51
}
},
.flags = 534,
.sp = 0xc0016d3ee0,
{
.ss = 43,
.ssx = 43,
.fred_ss = {
.ss = 43
}
}
}
↔ __sys_bpf [-EINVAL] 1.508us
› cmd = 0
› uattr = {
{
.kernel = 0xc0016d4360,
.user = 0xc0016d4360
}
}
› size = 80
← __x64_sys_bpf [-EINVAL] 3.270us
调用详情分析:
- 系统调用参数
ini
cmd = 0 # BPF_MAP_CREATE (创建 BPF map)
uattr = 0xc0016d4360 # 指向用户空间的 bpf_attr 结构
size = 80 # bpf_attr 结构的大小
- 返回结果 错误码: [-EINVAL] (无效参数)
问题分析 这个错误表明在尝试创建 BPF map 时,传递给内核的参数无效。结合 memleak.c 文件,可能的原因包括:
- Map 大小限制: 某个 map 的 max_entries 超出了系统限制
根因
c
#define PERF_MAX_STACK_DEPTH 128
...
__uint(value_size, PERF_MAX_STACK_DEPTH * sizeof(u64));
...
Linux 内核参数 PERF_MAX_STACK_DEPTH
的默认值是 127。
这个参数定义了 perf
工具在收集调用栈(call stack)时,能够记录的最大深度。也就是说,如果一个函数调用链的深度超过 127 层,perf
将只会记录前 127 层。
可以通过 /proc/sys/kernel/perf_event_max_stack
这个 sysctl 接口来查看和修改这个值。例如:
-
查看当前值:
bashcat /proc/sys/kernel/perf_event_max_stack
-
修改值 (例如,改为 256):
bashecho 256 > /proc/sys/kernel/perf_event_max_stack
请注意,增加 PERF_MAX_STACK_DEPTH
的值可能会增加 perf
在收集数据时的开销,因为它需要收集和存储更长的调用栈信息。