cachegrind.out 文件是 xdebug 生成的性能剖析二进制快照,本质为函数级调用耗时与内存占用的结构化纯文本记录,含 fl=(文件路径)、fn=(函数名)、calls=(调用来源)及以数字开头的耗时/内存行,需用 kcachegrind 等专用工具解析才能获得调用树、聚合视图和可视化分析。

什么是 cachegrind.out 文件?
它不是日志,是 Xdebug 生成的性能剖析(profiling)二进制快照,格式严格遵循 cachegrind 协议规范,本质是一份函数级调用耗时与内存占用的结构化记录。文件名后缀如 cachegrind.out.12345 中的数字是进程 PID 或时间戳,用于区分并发请求产生的多个文件。
cachegrind.out 文件里到底存了什么?
内容全是纯文本,但字段密集、缩进固定,人眼直接读非常吃力。核心字段包括:
-
fl=:函数所在文件路径(fl=/var/www/app/Controller.php) -
fn=:函数名(fn=App\Controller::index) -
0开头的行:该函数被调用次数(0 12表示调用了 12 次) -
calls=:调用来源(calls=1 0x12345表示被第 1 行、地址 0x12345 处调用) -
1开头的行:每行对应一次调用的耗时(微秒)、内存变化(字节)等,例如1 12450 8192
注意:cachegrind.out 不记录变量值、不包含堆栈帧详情,也不含 SQL 或 HTTP 请求上下文 —— 它只回答“哪个函数花了多少时间、占了多少内存”。
为什么不能直接 cat cachegrind.out.12345 分析?
因为可读性极差,且缺乏聚合视图。比如一个函数被调用 200 次,就会有 200 行 1 ... 数据,人工没法看出总耗时或平均耗时。更关键的是:
Xdebug 3.4.1 是一款功能强大的 PHP 调试扩展工具,于 2025 年 1 月 6 日正式发布。作为 Xdebug 3.4 系列的首个修复版本,3.4.1 版在继承上一版本强大功能的同时,重点解决了稳定性问题。该版本不仅修复了访问超全局变量时可能引发的程序崩溃现象,还增强了对 Windows 平台 PIE 构建机制的支持,为广大 PHP 开发者提供了更加稳定的调试环境。这一版本适合所有
- 没有调用树(Call Graph)可视化,看不出谁在调用谁、哪一层嵌套最深
- 无法按耗时排序、过滤高频低耗函数、标记内存泄漏嫌疑点
- 不支持点击跳转到源码位置(除非工具集成 IDE)
所以必须用 KCacheGrind、QCacheGrind 或 WebGrind 这类专用工具加载,它们会解析文本、构建调用关系、渲染火焰图式视图,并提供搜索、过滤、导出 CSV 等能力。
常见误配导致 cachegrind.out 文件为空或不生成
不是所有 xdebug.mode=profile 配置都能顺利落地。容易踩的坑有:
-
xdebug.output_dir目录不存在或 PHP 进程无写权限(检查ls -ld /tmp/xdebug和ps aux | grep php用户) - 启用了
xdebug.start_with_request=no,但没带触发参数(如XDEBUG_TRIGGER=perf-trigger),结果根本没启动 profiler - 同时开了
xdebug.mode=debug,profile,但远程调试连接失败,Xdebug 3.3+ 会静默禁用部分功能以保稳定 - 使用了轻量级采样模式(
xdebug.mode=lightweight),它不生成cachegrind.out,而是输出trace.*类型文件
最稳妥的验证方式是:访问页面后立刻执行 ls -t /tmp/xdebug/cachegrind.out.* | head -n 3,确认文件存在且大小 > 0KB。
真正难的不是生成文件,而是理解它和真实请求生命周期之间的映射关系——比如一个 AJAX 请求可能触发多个 PHP 进程,每个生成独立 cachegrind.out;而一个 CLI 脚本若未显式启用 profile,哪怕配置了全局 mode 也不会落盘。这些边界情况,往往比工具操作本身更消耗排查时间。










