核心问题是数据未释放、查询非流式、日志缓存累积;需逐层排查:加错误显示、查内存峰值、禁用chunk改游标分页、清理静态变量与日志、换流式组件、调优CLI配置。

ThinkPHP6 定时任务内存溢出,核心问题不在“任务本身多大”,而在于执行过程中数据没释放、查询没流式、日志或缓存越积越多。直接调高 memory_limit 只是掩盖症状,必须从运行链路逐层排查。
看错误源头:确认是不是真 OOM
先别急着改配置。在定时任务脚本(如 php think queue:work 或自定义命令)开头加两行:
再配合日志定位:
- CLI 模式下执行
php -i | grep memory_limit,确认 CLI 使用的 ini 文件和限制值(常与 Web 不同) - 在命令中加入
echo "Memory: " . memory_get_usage() . "\n";打点观察峰值 - 检查
runtime/log/下对应日期的日志,搜索Allowed memory size exhausted和堆栈位置
查数据库操作:避免全量加载
定时任务里最常见雷区是“查完再处理”——比如导出、同步、统计类任务,用 select() 或 chunk() 加载几万条进内存,立刻爆掉。
- 禁用
chunk():它仍会把每批结果完整载入数组,不适合百万级场景 - 改用生成器模拟游标分页:基于
id > $lastId分页拉取,每次只处理一页,处理完自动释放 - 排序字段必须有索引且尽量唯一(首选自增
id),避免时间戳重复导致漏数据 - 原生 SQL 查询后,及时
unset($result),尤其Db::query()返回大结果集时
盯住资源残留:静态变量、日志、临时文件
很多 OOM 发生在“看起来很轻”的地方:
- 自定义命令类里用了
private static $cache = [],循环中不断push,不清理就累积到爆炸 - 任务中写了
Log::debug($hugeData)或dump($data),日志内容驻留内存直到请求结束 - Excel 导入用了 PhpSpreadsheet 加载整表,50 万行轻松吃掉 2GB;应换 Spout 流式读,内存恒定 3–5MB
- 临时文件没
unlink(),尤其上传解析后未清理,反复执行撑爆磁盘+影响后续操作
调环境与配置:别让 PHP 自己扛不住
基础配置不到位,再好的逻辑也白搭:
- CLI 的
php.ini必须单独设置memory_limit = 512M(不是 -1),并确认生效:php -r "echo ini_get('memory_limit');" - 关掉调试:确保
app_debug = false,否则 SQL 日志、模板编译、错误堆栈全开,徒增 30%+ 内存 - 队列驱动选 Redis 而非 database:避免 jobs 表锁表 + 日志写入拖慢,database 驱动在高并发下易堆积
- 每批插入用
Db::insertAll()分片(200–500 条/批)+ 单事务 +gc_collect_cycles(),别用saveAll()
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











