Laravel 6.x 本身不导致 phpredis 内存溢出,问题根源在于业务代码误用:如未显式关闭 new Redis 实例、pipeline/multi 后未 exec、循环中重复创建连接、或高频写入无 TTL 的大缓存键,导致连接泄漏、缓冲区堆积与键值累积三重叠加。

直接结论:Laravel 6.x 本身不导致 phpredis 内存溢出,问题一定出在业务代码对 Redis 实例的误用或未释放,尤其是长连接、大值写入、未关闭管道、或循环中反复 new Redis 实例。
为什么 Laravel 6.x 的 phpredis 容易内存暴涨
Laravel 6.x 默认使用 Predis 作为 Redis 客户端,但若你显式切换为 phpredis(通过 extension=redis.so + REDIS_CLIENT=phpredis),就必须直面其 C 扩展的内存管理特性:它不会自动 GC 连接对象,也不会主动释放大响应缓冲区。
- 常见错误是手动 new
Redis实例后未调用close()或让其自然销毁(PHP 7.4+ 后析构更严格,但仍有风险) - 用
pipeline()或multi()后忘记exec(),导致命令队列和响应缓冲区持续累积 - 批量读取大 Key(如
HGETALL返回数万字段)时,PHP 变量直接承载全部数据,memory_get_usage()会立刻飙升 - Laravel 的
Cache::store('redis')底层复用连接,但若你在命令行任务或队列中频繁resolve('redis')并长期持有,连接池失效,连接数和内存同步增长
如何用 memory_get_usage 定位泄漏点
不要依赖日志或监控曲线——在疑似代码段前后加 memory_get_usage(true)(含真实内存分配),看差值:
echo "before: " . memory_get_usage(true) . "\n";
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// ... 执行 HGETALL 或 MGET 大量 key
echo "after: " . memory_get_usage(true) . "\n";
$redis->close(); // 必须显式 close
echo "after close: " . memory_get_usage(true) . "\n";
若 “after close” 仍比 “before” 高数百 MB,说明:要么有其他变量引用了返回的大数组,要么你没真正释放(比如用了 unset($redis) 却没 close())。
立即学习“PHP免费学习笔记(深入)”;
-
memory_get_usage(true)比memory_get_usage()更准,它返回的是 ZendMM 分配器实际申请的内存块大小 - 注意:CLI 模式下 PHP 不会自动回收 long-running 进程中的内存,必须靠显式释放
- 避免在循环里重复 new
Redis;改用单例或 Laravel 的RedisManager实例
phpredis 管道/事务未完成导致的隐性 OOM
这是 Laravel 6.x 项目中最隐蔽的内存陷阱:pipeline() 和 multi() 调用后若没执行 exec() 或发生异常中断,所有待执行命令及其预期响应缓冲区会滞留在 C 层,PHP 层无法感知,memory_get_usage() 也测不到,但 top 里 php 进程 RSS 持续上涨。
- 检查所有
$redis->pipeline()调用,确认每个都配对$redis->exec(),且放在try/catch中保证执行 - 禁用
pipeline()测试:把$redis->pipeline()->hgetall(...)->exec()拆成单条$redis->hGetAll(),观察内存是否回落 - 用
CLIENT LIST查看连接的qbuf和omem:若omem > 10MB,说明输出缓冲区已堆积,大概率是 pipeline 卡住了
laravel_cache 前缀键堆积引发的间接 OOM
Laravel 6.x 的缓存默认用 cache: 前缀,但如果你在队列任务或定时任务中高频写入未设 TTL 的键(如 cache:report_20260916),Redis 的 used_memory 会缓慢上升。而 phpredis 本身不触发淘汰——淘汰由 Redis server 决定,但若配置的是 noeviction 策略,就会在写入时直接报 OOM command not allowed 错误。
- 运行
redis-cli --scan --pattern "cache:*" | wc -l看缓存键数量,超 100 万需警惕 - 检查
CONFIG GET maxmemory-policy,确保不是noeviction;生产环境推荐allkeys-lru或volatile-lfu - 用
redis-cli MEMORY USAGE "cache:xxx"抽样几个键,确认单个缓存值是否过大(>1MB) - 强制清理:在 Artisan 命令中用
Cache::store('redis')->flush(),但注意这会清空整个 store,非紧急勿用
最常被忽略的是:phpredis 的内存泄漏往往不是单次操作造成,而是连接未 close + pipeline 卡住 + 大值缓存三者叠加,在长时间运行的队列 worker 中逐轮恶化。别只盯着 php.ini 的 memory_limit,先查 redis-cli CLIENT LIST 里的 omem 和 qbuf ——那才是真实的“内存黑洞”入口。



















