为何Linux perf会报告超出内核空间范围的地址?
关于perf报告中超出内核符号范围的异常地址解析
这些超出内核主镜像符号范围的高地址,通常是以下几种情况之一:
- 内核模块的代码地址:内核主镜像的地址范围是固定的,但动态加载的内核模块(如网卡驱动、文件系统驱动、KVM模块等)会被映射到主镜像之外的高地址区域。如果perf没有加载对应模块的符号表,就会直接显示原始地址而非符号名。你可以用
lsmod查看当前加载的模块,再通过modinfo <模块名>找到模块路径,手动用perf buildid-cache --add <模块路径>导入符号表,重新解析perf数据。 - JIT编译生成的代码地址:如果你的mysqld启用了JIT编译特性(比如MySQL 8.0+的
jit参数开启),或者依赖的库生成了JIT代码,这类代码会被映射到进程地址空间的高地址区域。perf默认不会自动解析JIT代码的符号,需要提前配置perf支持JIT符号解析,比如设置PERF_JITDUMP_DIR环境变量让JIT生成符号文件,再用perf inject -j -i perf.data -i perf.data.jit -o perf.data.jit处理后再执行perf report。 - 采样地址错位或硬件/软件bug:LBR(Last Branch Record)采样依赖CPU硬件特性,部分情况下会因为分支预测、指令重排序、跨CPU采样同步问题,导致记录的地址出现偏差;也可能是特定内核版本与perf工具的兼容性bug,导致地址解析错误。可以尝试换用
--call-graph dwarf采样方式对比结果,排查是否是LBR采样的问题。 - 内核高端内存映射区域:如果系统启用了高端内存相关配置(如大页、CONFIG_HIGHMEM),部分内核数据或代码会被映射到主镜像之外的高地址区域,而你查看的内核符号列表仅包含主镜像的符号,未覆盖这些扩展区域。可以用
cat /proc/kallsyms查看完整的内核符号(包括模块和高端内存区域的符号),对比异常地址是否在其中。
补充验证方法:执行
perf probe --add ffffffff a64000aa(注意去掉地址中间的空格),如果提示该地址属于某个模块,就能确认是模块地址;如果提示在用户空间,那大概率是JIT代码。
内容的提问来源于stack exchange,提问作者Tony Su
相关产品推荐
相关产品推荐

