frankenphp流量回落但rss不下降是正常现象,因php内存分配器保留空闲页供复用;需关注memory_get_peak_usage(true)是否持续上涨、frankenphp_queue_depth是否归零及隐式强引用是否切断。

FrankenPHP 流量回落但内存(RSS)不下降,是 Worker 模式下的预期行为,不是故障——PHP 进程不会主动把空闲内存页还给操作系统,而是留着复用;真正要盯的是 memory_get_peak_usage(true) 是否持续上涨、frankenphp_queue_depth 是否归零、以及是否存在隐式强引用未切断。
为什么 RSS 不降是正常现象
PHP 底层使用 glibc malloc 等分配器,释放的内存块默认保留在进程堆中,供后续请求复用。这避免了频繁系统调用 brk()/mmap() 的开销。表现就是:memory_get_usage(false)(脚本实际用量)会下降,但 memory_get_usage(true)(真实分配量)和 ps aux 显示的 RSS 值基本不变。
- 监控工具(如
ps、top、Prometheus 的process_resident_memory_bytes)看到的“不降”,本质是复用成功,不是泄漏 - 只要
memory_get_peak_usage(true)在连续请求中不单调递增,就说明 PHP 层内存管理健康 - OPcache、Symfony 容器、autoload 类映射等常驻内存,本就不该随流量回落而释放
流量回落时内存该有的健康信号
真正的稳定性指标不是 RSS 下降,而是它在小幅波动后收敛。你需要确认以下三点是否同时满足:
-
watch -n 1 'ps -o pid,rss,comm -p $(pgrep -f "frankenphp-worker")'中rss值在 ±5MB 内抖动,且 5 分钟内无持续上升趋势 -
frankenphp_queue_depth指标回落至 0 并稳定保持,说明无积压请求在占用内存 - 在控制器开头加
error_log('peak: ' . memory_get_peak_usage(true));,发 100 次请求后日志里数值集中在某个区间(如 8.2M–9.7M),而非逐次跳高(8.2M → 9.1M → 10.3M)
哪些情况才真要干预
RSS 不降本身不用处理,但若伴随以下现象,说明有隐藏泄漏或配置失衡,必须立即排查:
-
memory_get_peak_usage(true)在单个 worker 生命周期内持续线性上涨(每百请求涨 ≥2MB),且gc_collect_cycles()后无回落 -
/proc/$(pgrep -f frankenphp)/status中VmRSS在 30 分钟内上涨超 100MB,且无opcache_reset()或clearstatcache()等主动释放动作 - 日志中频繁出现
Worker #X restarted after max_requests,但max_requests设得过高(如 >1000)或过低(如 -
get_declared_classes()输出中仍存在Profiler、DebugBundle、TraceableEventDispatcher等调试类,说明 debug 组件未彻底卸载
别踩的典型坑
很多团队误把“RSS 不降”当问题去硬调,结果引入新风险:
- 盲目设
memory_limit = 512M—— 单请求限制变大,掩盖泄漏,最终触发 OOM Killer 杀死整个容器,无日志可查 - 禁用
opcache.enable_cli = 0后又没清缓存 —— OPcache 失效,worker 每次请求重编译类,内存阶梯上涨 - 在
register_shutdown_function()里调$em->clear()—— Worker 模式下该函数不保证执行,清理逻辑直接丢失 - 只看
memory_get_usage()日志 —— 它不含已分配但未使用的内存块,容易误判“内存已释放”
最易被忽略的点:内存是否“稳定”不取决于它落没落下,而取决于它涨不涨。盯住 memory_get_peak_usage(true) 的走势、frankenphp_queue_depth 的清空速度、以及调试组件是否真的从 autoloader 里消失——这三个信号比任何 RSS 数值都可靠。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











