关于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 相关文章推荐
php网站来路获取代码(针对搜索引擎)
Jun 08 PHP
php file_put_contents()功能函数(集成了fopen、fwrite、fclose)
May 24 PHP
php入门学习知识点七 PHP函数的基本应用
Jul 14 PHP
基于PHP生成静态页的实现方法
May 10 PHP
解析PHP中一些可能会被忽略的问题
Jun 21 PHP
PHP判断用户是否已经登录(跳转到不同页面或者执行不同动作)
Sep 22 PHP
php实现文件管理与基础功能操作
Mar 21 PHP
PHP实现的登录页面信息提示功能示例
Jul 24 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
Jun 16 PHP
PHP crc32()函数讲解
Feb 14 PHP
laravel 查询数据库获取结果实现判断是否为空
Oct 24 PHP
discuz论坛更换域名,详细文件修改步骤
Dec 09 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
php session应用实例 登录验证
2009/03/16 PHP
php使用date和strtotime函数输出指定日期的方法
2014/11/14 PHP
php微信开发之批量生成带参数的二维码
2016/06/26 PHP
php删除二维数组中的重复值方法
2018/03/12 PHP
清除网页历史记录,屏蔽后退按钮!
2008/12/22 Javascript
jQuery选择没有colspan属性的td的代码
2010/07/06 Javascript
JavaScript中的DSL元编程介绍
2015/03/15 Javascript
优化RequireJS项目的相关技巧总结
2015/07/01 Javascript
css如何让浮动元素水平居中
2015/08/07 Javascript
跟我学习javascript的定时器
2015/11/19 Javascript
基于jQuery实现返回顶部实例代码
2016/01/01 Javascript
Web前端开发工具——bower依赖包管理工具
2016/03/29 Javascript
jQuery下拉菜单的实现代码
2016/11/03 Javascript
JavaScript实现256色转灰度图
2017/02/22 Javascript
浅谈原生JS中的延迟脚本和异步脚本
2017/07/12 Javascript
使用FileReader API创建Vue文件阅读器组件
2018/04/03 Javascript
JS温故而知新之变量提升和时间死区
2019/01/27 Javascript
如何使用webpack打包一个库library的方法步骤
2019/12/18 Javascript
JavaScript缺少insertAfter解决方案
2020/07/03 Javascript
JavaScript实现点击图片换背景
2020/11/20 Javascript
Python字符串格式化输出方法分析
2016/04/13 Python
在python中按照特定顺序访问字典的方法详解
2018/12/14 Python
解决pyinstaller打包pyqt5的问题
2019/01/08 Python
pandas 空数据处理方法详解
2019/11/02 Python
Python数据存储之 h5py详解
2019/12/26 Python
Staples英国官方网站:办公用品一站式采购
2017/10/06 全球购物
Nisbets爱尔兰:英国最大的厨房和餐饮设备供应商
2019/01/26 全球购物
捷克建筑材料网上商店:DEK.cz
2021/03/06 全球购物
财务会计专业应届毕业生求职信
2013/10/18 职场文书
学生学习总结的自我评价
2013/10/22 职场文书
一名毕业生的自我鉴定
2013/12/04 职场文书
房产买卖委托公证书
2014/04/04 职场文书
教师廉洁自律承诺书
2014/05/26 职场文书
父亲节活动策划方案
2014/08/24 职场文书
2014年打非治违工作总结
2014/11/13 职场文书
我收到了德劲DE1107
2022/04/05 无线电