opcache_get_status()可直接获取opcache实时状态,命中率需计算:$status['opcache_hit_rate'](php 8.0+)或 hits/(hits+misses),内存使用需关注used_memory、free_memory及ooms次数,free_memory长期趋零或ooms>0表明内存不足。

用 opcache_get_status() 读取实时命中率和内存使用
PHP 自带的 opcache_get_status() 是最直接、无需额外扩展的方式,它返回一个包含运行时统计的数组。命中率不是直接字段,而是要自己算:用 opcache_hit_rate(PHP 8.0+)或手动计算 opcache_statistics['hits'] / (opcache_statistics['hits'] + opcache_statistics['misses'])。
内存“浪费”指标主要看三项:memory_usage['used_memory']、memory_usage['free_memory'] 和 opcache_statistics['ooms'](OOM 次数)。如果 free_memory 长期接近 0,或 ooms > 0,说明缓存空间已不够用,新脚本进不来,旧脚本被踢出,反而降低命中率。
-
opcache_get_status()默认只返回用户缓存信息;加参数true(即opcache_get_status(true))才包含详细脚本列表,但会显著拖慢响应,仅限调试时用 - 生产环境调用该函数前,建议加权限校验(如 IP 白名单或 token 验证),避免暴露敏感状态
- 命中率低于 90% 且
num_cached_scripts远小于max_accelerated_files,大概率是validate_timestamps=1导致频繁失效,而非内存不足
为什么不能只看 opcache_hit_rate 数值?
PHP 8.2 的 opcache_hit_rate 是浮点数,单位为百分比(比如 94.23),但它只统计「请求执行阶段」的命中,不包括 CLI 脚本、include 动态路径、或被 opcache.blacklist_filename 排除的文件。所以你看到 98%,实际业务里某些关键接口仍可能反复 miss——因为它们加载了黑名单里的配置文件,或用了 require_once __DIR__ . '/' . $name . '.php' 这类无法预判路径的写法。
- 动态文件名加载(如插件机制、模板自动发现)基本不会进 OPcache,
opcache_is_script_cached()对这类路径返回false - CLI 模式下运行的命令(如 Artisan、队列 worker)默认不参与 Web 请求的命中率统计,需单独用
opcache_get_status()并传['scripts' => true]查看 - 若启用了
opcache.preload,预加载脚本的命中不计入常规 hits/misses,但会提升整体启动速度,此时总命中率数字可能虚高
如何把命中率和内存数据接入监控系统?
不要手写轮询脚本去 curl 一个 status 页面。推荐两种轻量落地方式:
- 用
opcache_get_status()输出 JSON 到一个受限访问的 endpoint(如/opcache-status?token=xxx),再由 Prometheus 的blackbox_exporter或自定义 exporter 定期抓取。关键字段映射为指标:opcache_hit_rate→php_opcache_hit_rate_percent,memory_usage.free_memory→php_opcache_free_memory_bytes - 在 Laravel 或 Symfony 等框架中,用中间件或事件监听器,在每次请求结束前调用
opcache_get_status()抽样(比如每 100 次请求采一次),聚合后写入 Redis 的 hash(opcache:stats),再由后台任务定时上报。避免每次请求都查,也规避了高并发下opcache_get_status()的锁开销 - 注意:如果 PHP-FPM 开启了
opcache.enable_cli=0,那么通过php -r "print_r(opcache_get_status());"命令行查看的结果,和 FPM worker 进程里的状态完全无关——必须在相同 SAPI 环境下调用才准
容易被忽略的内存“浪费”真实来源
很多人盯着 free_memory 低就调大 memory_consumption,结果命中率没升反降。真正导致内存浪费的,常是这几件事:
- 大量匿名函数或闭包(尤其在 Laravel Service Provider 中动态注册回调),它们生成的 opcode 无法被复用,每次请求都新建一份,快速吃光内存
-
opcache.max_accelerated_files设得太小(比如 2000),而项目有 5000+ PHP 文件,OPcache 会用 LRU 策略踢旧脚本,但踢得不彻底,残留碎片多,interned_strings_buffer也会堆积无效字符串 - 启用了
opcache.save_comments=1(默认),但代码里塞了大量 PHPDoc 注释或内联 HTML,这些内容全进内存,却几乎不参与执行逻辑 - 部署时没清缓存,旧版本文件还占着内存,新版本进来只能挤占空间——这时候
opcache_reset()比调大内存更有效
opcache_get_status()['scripts'])和业务日志交叉验证。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











