FrankenPHP中memory_get_peak_usage持续上涨不等于内存泄漏,需结合RSS增长趋势、JIT缓存状态及静态变量累积情况综合判断:若每轮稳定+6KB无衰减才是泄漏,收敛则属正常缓存填充。

FrankenPHP 中 memory_get_peak_usage 持续上涨 ≠ 内存泄漏
FrankenPHP 是基于 SAPI 的常驻进程模型,其内存行为和传统 PHP-FPM 有本质差异:OPcache 编译产物、HTTP 连接池、路由缓存、静态变量都会长期驻留。单纯看 memory_get_peak_usage(true) 每轮 +4KB 就断定泄漏,大概率误判。
关键区分点在于增长是否「收敛」:若压测 500 轮后内存增量从 +8KB/轮衰减到 +0.2KB/轮并稳定,属于缓存填充;若每轮稳定 +6KB 且无衰减趋势,才是泄漏信号。
- 用
memory_get_peak_usage(true)在请求循环首尾打点,记录差值序列,画折线图比看单次值更可靠 - 对比
ps aux --sort=-%mem | head -n 5中 FrankenPHP worker 的 RSS 增长曲线 —— 若 RSS 持续爬升而 PHP 层memory_get_usage()增幅平缓,问题在 C 层(如扩展、HTTP 连接未 close) - 检查
opcache_get_status()['opcache_statistics']['oom_restarts']是否非零,OOM 重启会重置 PHP 层内存计数,但 RSS 不降,易掩盖真实泄漏
OPcache JIT 缓存 vs 真实泄漏的识别方法
FrankenPHP 默认启用 JIT(opcache.jit=1205),JIT 编译后的机器码直接占驻物理内存,不走 PHP 堆管理,memory_get_usage() 完全不可见。但 opcache_get_status() 的 jit['function_count'] 和 jit['memory_usage'] 会暴露问题。
- 执行
opcache_get_status(),重点观察jit['function_count']是否随请求数线性增长(比如每 100 次请求 +12 个函数),而非趋于稳定 - 对比
jit['memory_usage']与opcache.jit_buffer_size配置值:若前者长期 >90% buffer_size 且持续上涨,说明 JIT 编译残留严重,不是缓存而是泄漏 - 临时设
opcache.jit=0并 reload 进程,观察 RSS 是否显著回落 —— 若回落超 30%,基本锁定 JIT 层编译失控,常见于模板引擎动态生成匿名函数、或配置未加载导致重复解析同一文件
全局/静态变量累积是 FrankenPHP 最常见“伪泄漏”
FrankenPHP worker 生命周期长达数小时甚至数天,static $cache = [] 或 global $registry 不会随请求结束销毁。这类累积看起来像泄漏,实则是设计使然,但需确认是否可控。
立即学习“PHP免费学习笔记(深入)”;
- 搜索代码中所有
static声明,检查是否有未设上限的数组追加(如$log[] = $entry)、未清理的闭包注册(如事件监听器未removeListener) - 用
gc_collect_cycles()后立刻调用memory_get_usage(),若降幅极小( - 对关键静态容器加 size 限制和淘汰策略,例如:
if (count(self::$data) > 1000) { array_shift(self::$data); },避免无界增长
真正泄漏往往藏在资源未释放和扩展交互里
FrankenPHP 的 HTTP/2 支持、连接池、协程调度依赖底层 C 扩展,这些地方出问题时,memory_get_usage() 完全不体现,但 ps 看 RSS 暴涨,且 strace -p $(pidof frankenphp) -e trace=brk,mmap 会显示大量 mmap 调用。
- 检查所有
curl_init()、fopen()、mysqli_connect()调用后是否配对curl_close()、fclose()、mysqli_close()—— CLI 模式下不关句柄,句柄和关联缓冲区会一直占内存 - 禁用所有非核心 PECL 扩展(如
redis、grpc),只留opcache和json,观察 RSS 是否稳定;若稳定,逐个启用排查 - 启动 FrankenPHP 时加
-v参数,留意日志中是否出现Failed to allocate xxx bytes或Out of memory (allocated: xxx)—— 这类错误来自 Zend 内存管理器,指向 PHP 层真泄漏
mmap 和 brk 行为,而不是盯着 memory_get_peak_usage() 反复刷新。



















