FrankenPHP空闲内存基准是启动后未处理请求时的RSS值,需用ps命令抓取所有worker进程RSS总和,典型范围40–80MB,主要受OPcache配置影响。

启动后立刻测 RSS,别等请求进来
FrankenPHP 的“空闲内存”不是指刚解压完二进制那一刻的值,而是指 frankenphp run 成功启动、主线程就绪、但尚未处理任何 HTTP 请求时的常驻内存。这个值才是后续性能对比和资源规划的基准线。此时 PHP worker 进程已初始化完毕,OPcache 已加载(如果启用),但 Symfony/Laravel 容器、路由缓存、数据库连接池等都未触发。
- 用
pgrep -f "frankenphp run"拿到主进程 PID,再读/proc/$PID/status中的VmRSS字段:它代表实际物理内存占用(单位 kB) - 更直接的做法是:
ps -o pid,rss,comm -p $(pgrep -f "frankenphp run")—— 看RSS列数值,单位是 KB - 别用
top或htop手动记数:它们默认刷新间隔 3 秒,可能错过刚启动那一瞬间的最低值;且 UI 渲染本身会引入微小偏差 - 如果启用了 worker 模式,
ps会显示多个frankenphp-worker进程,此时应取所有 worker 进程RSS的总和,而非只看主进程
worker 模式下空闲内存 ≠ 单个 worker 的 RSS
FrankenPHP 的 worker 进程在空闲时仍会持有 OPcache 缓存、Composer 自动加载映射表、以及部分框架静态结构(如 Symfony 的编译容器骨架)。这些不是“垃圾”,而是为后续请求预热的必要开销。所以你看到的空闲 RSS,其实是“最小可服务状态”的内存基线。
- 空闲时每个
frankenphp-worker的 RSS 通常在 40–80 MB(取决于框架大小和 OPcache 配置),不是几 MB -
opcache.memory_consumption=256会直接抬高这个基线——哪怕没跑任何 PHP 脚本,OPcache 共享内存段也已分配 - 如果你发现空闲 RSS > 120 MB,大概率是
opcache.max_accelerated_files设得过大(比如 100000),导致 OPcache 预分配了远超实际需要的哈希表空间 - 验证方式:临时把
opcache.enable=0,重启 FrankenPHP,再测 RSS —— 若下降明显(如从 95MB → 32MB),说明 OPcache 是主要 contributor
别被 memory_get_usage() 欺骗
memory_get_usage() 返回的是 PHP 用户态堆内存,不包含 OPcache 共享内存、ZEND 引擎全局结构、或 Go 主进程本身的开销。它对空闲测量几乎无意义——worker 空闲时该函数常返回 2–4 MB,但这只是冰山一角。
- 真正要盯的是系统级
VmRSS或ps的RSS,它们反映真实物理内存压力 -
memory_get_peak_usage(true)在空闲时也接近memory_get_usage(true),因为没执行过任何脚本,峰值不会高于当前值 - 想定位 PHP 层面的内存大户?等有请求进来后,在关键位置(如控制器开头/结尾)打点记录
memory_get_usage(true),再对比日志差值
容器环境要减去 cgroup 开销干扰
在 Docker 或 Kubernetes 中运行时,ps 和 /proc/PID/status 读出的 RSS 包含了 Go 运行时的 goroutine 栈、net/http 连接池预分配内存等,这些和 PHP 无关但属于 FrankenPHP 进程本身。若需排除干扰,可对比同一镜像下 “仅启动不监听” 和 “启动并监听端口” 的 RSS 差值。
立即学习“PHP免费学习笔记(深入)”;
- 用
docker run --rm -it your-frankenphp-image /bin/sh -c 'frankenphp run --document-root /dev/null & sleep 1; ps -o pid,rss,comm -p $(pgrep frankenphp)'快速抓取启动瞬时值 - 确保测试前清空 OPcache:
opcache_reset()或重启容器,避免上一次运行残留影响 - 注意:Alpine 镜像因 musl libc 行为差异,RSS 常比 Debian 镜像低 15–20%,跨镜像对比必须统一基础系统
ps RSS,以及确认是否真的没有请求触发任何 PHP 执行逻辑。其余一切指标,都是噪音。



















