关于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 相关文章推荐
PHPMailer 中文使用说明小结
Jan 22 PHP
晋城吧对DiscuzX进行的前端优化要点
Sep 05 PHP
一个PHP缓存类代码(附详细说明)
Jun 09 PHP
php数组函数序列之rsort() - 对数组的元素值进行降序排序
Nov 02 PHP
基于PHP静态类的原罪详解
May 06 PHP
深入php var_dump()函数的详解
Jun 05 PHP
php中如何使对象可以像数组一样进行foreach循环
Aug 09 PHP
php实现的debug log日志操作类实例
Jul 12 PHP
thinkphp ajaxfileupload实现异步上传图片的示例
Aug 28 PHP
Laravel中日期时间处理包Carbon的简单使用
Sep 21 PHP
PDO::commit讲解
Jan 27 PHP
PHP7数组的底层实现示例
Aug 25 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
重量级动漫纷纷停播!唯独OVERLORD第四季正在英魂之刃继续更新
2020/05/06 日漫
为了这两部电子管收音机,买了6套全新电子管和10粒刻度盘灯泡
2021/03/02 无线电
php调用mysql存储过程
2007/02/14 PHP
将文件夹压缩成zip文件的php代码
2009/12/14 PHP
深入file_get_contents函数抓取内容失败的原因分析
2013/06/25 PHP
PHP写的资源下载防盗链类分享
2014/05/12 PHP
php中数字、字符与对象判断函数用法实例
2014/11/26 PHP
PHP 进度条函数的简单实例
2017/09/19 PHP
jQuery textarea的长度进行验证
2009/05/06 Javascript
JS取文本框中最小值的简单实例
2013/11/29 Javascript
jquery mobile动态添加元素之后不能正确渲染解决方法说明
2014/03/05 Javascript
初步使用Node连接Mysql数据库
2016/03/03 Javascript
jQuery 中的 DOM 操作
2016/04/26 Javascript
angular源码学习第一篇 setupModuleLoader方法
2016/10/20 Javascript
jQuery返回定位插件详解
2017/05/15 jQuery
React为 Vue 引入容器组件和展示组件的教程详解
2018/05/03 Javascript
Bootstrap 实现表格样式、表单布局的实例代码
2018/12/09 Javascript
vue项目中运用webpack动态配置打包多种环境域名的方法
2019/06/24 Javascript
js在HTML的三种引用方式详解
2020/08/29 Javascript
[08:07]DOTA2每周TOP10 精彩击杀集锦vol.8
2014/06/25 DOTA
django基础之数据库操作方法(详解)
2017/05/24 Python
利用Python如何生成hash值示例详解
2017/12/20 Python
Python 最大概率法进行汉语切分的方法
2018/12/14 Python
如何在django里上传csv文件并进行入库处理的方法
2019/01/02 Python
Python3.0中普通方法、类方法和静态方法的比较
2019/05/03 Python
搭建python django虚拟环境完整步骤详解
2019/07/08 Python
Python空间数据处理之GDAL读写遥感图像
2019/08/01 Python
python中wx模块的具体使用方法
2020/05/15 Python
CSS3对背景图片的裁剪及尺寸和位置的设定方法
2016/03/07 HTML / CSS
*p++ 自增p 还是p所指向的变量
2016/07/16 面试题
日语专业毕业生求职信
2013/12/04 职场文书
创业计划书中要认真思考的问题
2013/12/28 职场文书
财务会计专业个人求职信范本
2014/01/08 职场文书
母亲节感恩活动记录
2014/03/16 职场文书
2014年清明节寄语
2014/04/03 职场文书
html+css实现环绕倒影加载特效
2021/07/07 HTML / CSS