关于Yii2框架跑脚本时内存泄漏问题的分析与解决


Posted in PHP onDecember 01, 2019

现象

在跑 edu_ocr_img 表的归档时,每跑几万个数据,都会报一次内存耗尽

PHP Fatal error:  Allowed memory size of 134217728 bytesexhausted (tried toallocate 135168 bytes)

跟踪代码发现,是在插入时以下代码造成的:

EduOCRTaskBackup::getDb()->createCommand()->batchInsert(EduOCRTaskBackup::tableName(), $fields, $data)->execute();

execute 之后会造成使用内存涨上去,并且在之后 unset 所有变量内存也会有一部分不会删除,直到内存耗尽。

于是跟踪到 Yii2中execute的具体代码块发现在记录 log 的时候会将使用很高的内存,分析代码之后得出造成泄漏的代码块如下:

造成泄漏的代码块

/**
 * Logs a message with the given type and category.
 * If [[traceLevel]] is greater than 0, additional call stack information about
 * the application code will be logged as well.
 * @param string|array $message the message to be logged. This can be a simple string or a more
 * complex data structure that will be handled by a [[Target|log target]].
 * @param integer $level the level of the message. This must be one of the following:
 * `Logger::LEVEL_ERROR`, `Logger::LEVEL_WARNING`, `Logger::LEVEL_INFO`, `Logger::LEVEL_TRACE`,
 * `Logger::LEVEL_PROFILE_BEGIN`, `Logger::LEVEL_PROFILE_END`.
 * @param string $category the category of the message.
 */
public function log($message, $level, $category = 'application')
{
 $time = microtime(true);
 $traces = [];
 if ($this->traceLevel > 0) {
  $count = 0;
  $ts = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  array_pop($ts); // remove the last trace since it would be the entry script, not very useful
  foreach ($ts as $trace) {
   if (isset($trace['file'], $trace['line']) && strpos($trace['file'], YII2_PATH) !== 0) {
    unset($trace['object'], $trace['args']);
    $traces[] = $trace;
    if (++$count >= $this->traceLevel) {
     break;
    }
   }
  }
 }
 
 // 这里是造成内存的罪魁祸首
 $this->messages[] = [$message, $level, $category, $time, $traces];
 if ($this->flushInterval > 0 && count($this->messages) >= $this->flushInterval) {
  $this->flush();
 }
}

造成内存泄漏的原因分析

在 Yii2框架中的 vendor/yiisoft/yii2/log/Logger.php:156 log函数的156行之后会判断 count($this->messages) >= $this->flushInterval

即:内存中存储的 message 的条数要大于等于预设的 $this->flushInterval 才会将内存中的message 刷到磁盘上去。

如果在刷新到磁盘之前就已经将 php.ini 设置的 128M 内存打满的话,会直接报错申请内存耗尽。

很多关于 YII2其他原因的内存泄漏的讨论
https://github.com/yiisoft/yii2/issues/13256

解决方案

在程序开始时,设置 flushInterval 为一个比较小的值

\Yii::getLogger()->flushInterval = 100; // 设置成一个较小的值

在程序执行过程中,每次 execute 之后对内存中的 message 进行 flush

\Yii::getLogger()->flush(true); // 参数传 true 表示每次都会将 message 清理到磁盘中

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
基于数据库的在线人数,日访问量等统计
Oct 09 PHP
php 面试碰到过的问题 在此做下记录
Jun 09 PHP
解决ajax+php中文乱码的方法详解
Jun 09 PHP
ThinkPHP使用PHPExcel实现Excel数据导入导出完整实例
Jul 22 PHP
php内存缓存实现方法
Jan 24 PHP
PHP图像裁剪缩略裁切类源码及使用方法
Jan 07 PHP
PHP使用反射机制实现查找类和方法的所在位置
Apr 22 PHP
SAE实时日志接口SDK用法示例
Oct 09 PHP
PHP实现上传多文件示例代码
Feb 20 PHP
laravel利用中间件防止未登录用户直接访问后台的方法
Sep 30 PHP
laravel 解决groupBy时出现的错误 isn't in Group By问题
Oct 17 PHP
PHP解决高并发的优化方案实例
Dec 10 PHP
详解no input file specified 三种解决方法
Nov 29 #PHP
设定php简写功能的方法
Nov 28 #PHP
如何在centos8自定义目录安装php7.3
Nov 28 #PHP
PHP的new static和new self的区别与使用
Nov 27 #PHP
Laravel 微信小程序后端实现用户登录的示例代码
Nov 26 #PHP
Laravel 微信小程序后端搭建步骤详解
Nov 26 #PHP
php 使用expat方式解析xml文件操作示例
Nov 26 #PHP
You might like
ThinkPHP php 框架学习笔记
2009/10/30 PHP
基于curl数据采集之单页面采集函数get_html的使用
2013/04/28 PHP
php+jQuery.uploadify实现文件上传教程
2014/12/26 PHP
PHP按一定比例压缩图片的方法
2018/10/12 PHP
javascript window对象属性整理
2009/10/24 Javascript
jQuery动态地获取系统时间实现代码
2013/05/24 Javascript
jquery操作下拉列表、文本框、复选框、单选框集合(收藏)
2014/01/08 Javascript
AngularJS中的模块详解
2015/01/29 Javascript
jquery实现经典的淡入淡出选项卡效果代码
2015/09/22 Javascript
跟我学习javascript的this关键字
2020/05/28 Javascript
Bootstrap每天必学之按钮(一)
2015/11/24 Javascript
javaScript数组迭代方法详解
2016/04/14 Javascript
基于jQuery倒计时插件实现团购秒杀效果
2016/05/13 Javascript
如何判断Javascript对象是否存在的简单实例
2016/05/18 Javascript
jQuery获取多种input值的简单实现方法
2016/06/20 Javascript
easyui-combobox 实现简单的自动补全功能示例
2016/11/08 Javascript
Bootstrap弹出框modal上层的输入框不能获得焦点问题的解决方法
2016/12/13 Javascript
jQuery无刷新上传之uploadify简单代码
2017/01/17 Javascript
RequireJs的使用详解
2017/02/19 Javascript
对Vue beforeRouteEnter 的next执行时机详解
2018/08/25 Javascript
JavaScript常见事件处理程序实例总结
2019/01/05 Javascript
JS实现选项卡效果的代码实例
2019/05/20 Javascript
vue v-for 点击当前行,获取当前行数据及event当前事件对象的操作
2020/09/10 Javascript
[53:18]Spirit vs Liquid Supermajor小组赛A组 BO3 第三场 6.2
2018/06/03 DOTA
Python 学习笔记
2008/12/27 Python
mysql 之通过配置文件链接数据库
2017/08/12 Python
django 2.0更新的10条注意事项总结
2018/01/05 Python
深入分析python中整型不会溢出问题
2018/06/18 Python
如何理解Python中的变量
2020/06/01 Python
购买200个世界上最好的内衣品牌:Bare Necessities
2017/02/11 全球购物
秋季运动会加油稿200字
2014/01/11 职场文书
打架检讨书500字
2014/01/29 职场文书
悬空寺导游词
2015/02/05 职场文书
党员个人总结范文
2015/02/14 职场文书
评职称个人总结
2015/03/05 职场文书
windows11怎么查看自己安装的版本号? win11版本号的查看方法
2021/11/21 数码科技