Codeigniter中PHP Cron Job调用MySQL函数内存占用过高求助
我来帮你排查这个头疼的问题!Web访问正常但Cron Job执行内存暴增的情况,大多是两种运行模式的资源处理逻辑或配置差异导致的,下面给你一步步梳理解决方案:
1. 先排查PHP CLI与Web环境的配置差异
很多服务器上,PHP的Web和CLI模式用的是不同的php.ini配置文件,这很容易被忽略:
- 查看Web模式配置:在控制器里临时加一行
phpinfo();,通过浏览器访问查看 - 查看CLI模式配置:在服务器终端执行
php -i
重点对比这几个参数: memory_limit:CLI模式下如果设置为-1(无限制),加上脚本有内存泄漏,会快速耗尽内存,建议调整到合理值(比如512M)max_execution_time:CLI模式默认无超时限制,若脚本卡住会一直占用内存opcache.enable:如果CLI模式开启了OPcache但配置不当,可能导致缓存堆积
2. 强制释放数据库资源
在Web请求中,CodeIgniter会自动在请求结束时清理数据库连接和结果集,但CLI模式下必须手动处理,尤其是处理大量数据时:
- 每次查询(尤其是调用MySQL函数返回大结果集)后,调用
$this->db->free_result();释放结果集内存 - 脚本执行完成前,手动关闭数据库连接:
$this->db->close();
示例代码:
// 调用MySQL函数 $query = $this->db->query("SELECT your_mysql_function() AS result"); // 处理结果 $row = $query->row(); // 立即释放结果集 $query->free_result(); // 脚本结束前关闭连接 $this->db->close();
3. 分批处理大结果集,避免一次性加载
如果你的MySQL函数返回超大数据集,Web模式下可能因为输出缓冲或浏览器分段接收,内存占用不明显,但CLI模式会一次性把所有结果加载到内存里,直接导致内存暴涨。解决办法是逐行/分批处理:
- 使用CodeIgniter的
unbuffered_query()逐行读取结果:
$query = $this->db->unbuffered('SELECT * FROM your_table WHERE ...'); while ($row = $query->unbuffered_row()) { // 处理单条数据 // 及时销毁临时变量 unset($row); } $query->free_result();
- 如果需要分页处理,用
limit()+offset()分批次查询,每处理完一批就清理变量和结果集
4. 排查脚本中的内存泄漏
在脚本关键节点添加内存监控,定位内存增长的源头:
// 在循环、查询等关键步骤前后打印内存使用 echo '当前内存占用:' . memory_get_usage(true) . ' bytes' . PHP_EOL;
重点检查:
- 循环中是否有未销毁的大数组/对象,比如每次循环都往全局数组里追加数据却不清理
- 是否使用了静态变量/全局变量,导致数据累积
- 是否有未关闭的文件句柄、第三方服务连接等资源
5. 优化CodeIgniter CLI模式的资源加载
CLI模式下不需要加载Web相关的组件(比如会话、视图、缓存),可以手动禁用减少内存占用:
if (is_cli()) { // 禁用会话库(如果不需要) $this->load->library('session'); $this->session->sess_destroy(); // 关闭性能分析器 $this->output->enable_profiler(false); // 关闭输出缓冲,避免内存堆积 ob_end_flush(); }
6. 检查Cron Job的进程残留
如果Cron Job每次执行后进程没有正常退出,会变成僵尸进程累积占用内存:
- 执行
ps aux | grep php查看是否有大量残留的PHP进程 - 如果有,在Cron命令里添加超时限制,强制脚本在指定时间内结束:
*/4 * * * * timeout 300 php /path/to/your/codeigniter/index.php controller function
(上面的命令强制脚本5分钟内结束,避免进程挂起)
内容的提问来源于stack exchange,提问作者user8522353
相关产品推荐
相关产品推荐

