必须在每个接口入口和出口调用memory_get_peak_usage(true)测真实物理内存峰值,配合frankenphp_clear_globals()清全局变量、固定FRANKENPHP_WORKERS=1、opcache_reset()排除干扰,再结合/proc/[pid]/status观察VmRSS阶梯增长以区分合理开销与累积泄漏。

用 memory_get_peak_usage(true) 在每个接口入口打点
FrankenPHP 的内存开销差异,不能靠全局监控猜,得落到具体请求路径里测。最直接的方式是在每个路由对应的控制器或入口逻辑开头、结尾各调一次 memory_get_peak_usage(true),它返回的是当前请求执行期间占用的**真实物理内存峰值(字节)**,比 memory_get_usage() 更反映实际压力。
常见错误是只在结尾取值,忽略了中间峰值可能早已被 GC 回收——比如某次大数组解包占了 80MB,之后 unset 了,结尾只剩 2MB,但峰值已经触发过 OOM 风险。
- 必须传
true参数,否则返回的是 Zend 内存管理器分配的“虚拟块”,不等于 RSS - 不要放在 try/catch 外层统一捕获,异常中断时可能漏掉峰值记录
- 建议配合请求 ID(如
$_SERVER['HTTP_X_REQUEST_ID'])写入日志,方便后续按 trace 关联
启用 frankenphp_clear_globals() 避免跨请求污染干扰测量
Worker 模式下,$_SERVER、$_GET 等超全局变量默认不会自动重置,前一个请求残留的数据可能让后一个接口误判内存增长。比如某个接口把大 JSON 解析结果挂到 $GLOBALS['cache'],下一个轻量接口进来时,memory_get_peak_usage(true) 就会包含这部分“不属于它”的内存。
解决方法是在每个接口逻辑开始前显式调用:
立即学习“PHP免费学习笔记(深入)”;
frankenphp_clear_globals();
这个函数会清空所有 PHP 超全局数组(不含 $_COOKIE 和 $_SESSION),确保每次测量起点干净。注意它只在 FrankenPHP Worker 模式下有效,FPM 或 CLI 下调用无作用。
- 别依赖框架自动清理——Symfony/Laravel 默认不调用它
- 如果用了 APCu 或 OPcache 预加载,它们的内存不在此清理范围内,属正常复用
- 清除后
$_SERVER['REQUEST_URI']会变空,需提前缓存关键字段
对比时必须固定 FRANKENPHP_WORKERS 数量并关闭 OPcache 预热干扰
不同接口的内存表现,容易被线程池配置和缓存状态带偏。比如 A 接口先跑,触发了 OPcache 预热和类加载,B 接口再跑时看似内存更低,其实只是沾了光。
要公平对比,得控制变量:
- 启动前设环境变量
FRANKENPHP_WORKERS=1,避免多 worker 间内存统计混杂 - 压测前清空 OPcache:
opcache_reset(),或临时在 php.ini 中关掉opcache.enable=0 - 用
curl -H "X-FrankenPHP-Reset: 1"触发单次 worker 重启(需 Caddyfile 开启debug指令) - 每个接口单独跑一轮完整压测(如 k6 跑 100 次),取
memory_get_peak_usage(true)的 P95 值,而非平均值
用 /proc/[pid]/status 验证 PHP Worker 进程级内存是否稳定
接口级测量只能看到“请求内”开销,但真正影响服务稳定的是整个 Worker 进程的内存趋势。比如某个接口没泄漏,但它反复 new 大对象又不 unset,长期运行后 VmRSS 持续上涨,最终拖垮整个进程。
查法很简单:
cat /proc/$(pgrep -f "frankenphp.*worker")/status | grep -E "VmRSS|VmSize"
连续采样 5 分钟,观察 VmRSS(实际物理内存)是否阶梯式上升。如果某接口压测后 VmRSS 每分钟涨 10MB 且不回落,基本可判定有未释放资源。
-
VmRSS比ps aux显示的 %MEM 更准,后者是比例值,受系统总内存影响 - 别只看单次结果——Worker 进程内存是累积的,要测“长时间运行下的增量”
- 若发现
VmRSS异常,再回溯对应接口的memory_get_peak_usage(true)日志,定位具体哪次请求跳变
真正难的不是测出哪个接口内存高,而是区分它是「单次请求合理开销」还是「长期累积泄漏」。前者调优代码,后者得查连接池、静态缓存、OPcache 配置是否对齐——这些细节一漏,压测数据就全失真。



















