APCu 缓存本身不会直接导致内存溢出,但配置不当或滥用会加速内存耗尽;其共享内存独立于 memory_limit,需合理设置 apcu.shm_size、apcu.ttl 和 apcu.gc_ttl,并限制单条缓存大小、监控使用率及主动清理。
APCu 缓存本身不会直接导致内存溢出,但配置不当或滥用会加速内存耗尽
APCu 是用户级内存缓存(apcu_store / apcu_fetch),它把数据存在 PHP 进程共享内存里,不经过序列化、无网络开销,快是真快——但它的内存是“吃进去就不吐”的。一旦你缓存了 10 万个 2MB 的数组,哪怕只存 1 分钟,也立刻压爆 memory_limit。这不是 APCu 的 bug,而是你没给它划边界。
- APCu 不受
memory_limit管控:它用的是独立共享内存段(由apc.shm_size或apcu.shm_size控制),PHP 脚本的内存限制对它无效 - 默认配置极危险:很多发行版预装 APCu 时设
apcu.shm_size=32M,但没配apcu.ttl和apcu.gc_ttl,缓存永不回收 - 缓存键爆炸式增长:比如用时间戳+用户ID拼 key:
"user_{$uid}_{$time}",每秒生成新 key,旧 key 永不淘汰 → 内存只增不减
必须改的三个 APCu 配置项(php.ini)
别只调 memory_limit,那是治脚痛医头。真正要动的是 APCu 自己的“胃容量”和“消化规则”:
-
apcu.shm_size=64M:共享内存总大小,建议 64M–256M(根据服务器总内存按 5%–10% 设)。超过此值写入失败,但不会报错,apcu_store()返回false—— 很多代码没判这个,就默默失效 -
apcu.ttl=3600:每个缓存项默认存活时间(秒)。设为 0 表示永不过期,等于埋雷;生产环境务必设合理值(如 10 分钟=600,1 小时=3600) -
apcu.gc_ttl=3600:垃圾回收触发间隔(秒)。APCu 不是实时删过期 key,而是每gc_ttl秒扫一次内存。若gc_ttl > ttl,过期 key 可能卡住内存数小时
改完记得重启 PHP-FPM 或 Apache:APCu 共享内存段在进程启动时分配,热加载不生效。
代码层防溢出:存之前先问“值够小吗?”
APCu 存的是原始 PHP 变量,大数组、对象、资源句柄全照单全收。一个 file_get_contents('big.log') 直接塞进去,30MB 内存瞬间占满。