关于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 相关文章推荐
BBS(php & mysql)完整版(七)
Oct 09 PHP
比file_get_contents稳定的curl_get_contents分享
Jan 11 PHP
如何用php生成扭曲及旋转的验证码图片
Jun 07 PHP
Yii框架中 find findAll 查找出制定的字段的方法对比
Sep 10 PHP
php中spl_autoload详解
Oct 17 PHP
php cookie名使用点号(句号)会被转换
Oct 23 PHP
Yii2表单事件之Ajax提交实现方法
May 04 PHP
php面向对象的用户登录身份验证
Jun 08 PHP
PHP+redis实现的悲观锁机制示例
Jun 12 PHP
PHP如何根据文件头检测文件类型实例代码
Oct 14 PHP
Laravel框架实现超简单的分页效果示例
Feb 08 PHP
php简单计算权重的方法示例【适合抽奖类应用】
Jun 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
PHP实现的连贯操作、链式操作实例
2014/07/08 PHP
获取页面高度,窗口高度,滚动条高度等参数值getPageSize,getPageScroll
2006/09/22 Javascript
JQuery触发radio或checkbox的change事件
2012/12/18 Javascript
将两个div左右并列显示并实现点击标题切换内容
2013/10/22 Javascript
JS小功能(button选择颜色)简单实例
2013/11/29 Javascript
详解AngularJS中自定义过滤器
2015/12/28 Javascript
谈一谈javascript闭包
2016/01/28 Javascript
JavaScript程序中实现继承特性的方式总结
2016/06/24 Javascript
Bootstrap CSS布局之按钮
2016/12/17 Javascript
Node.js中用D3.js的方法示例
2017/01/16 Javascript
基于node.js依赖express解析post请求四种数据格式
2017/02/13 Javascript
vue-cli或vue项目利用HBuilder打包成移动端app操作
2020/07/29 Javascript
[00:37]2016完美“圣”典风云人物:AMS宣传片
2016/12/06 DOTA
python类继承与子类实例初始化用法分析
2015/04/17 Python
使用Python神器对付12306变态验证码
2016/01/05 Python
Python中字符串的常见操作技巧总结
2016/07/28 Python
Python向日志输出中添加上下文信息
2017/05/24 Python
Python实现对象转换为xml的方法示例
2017/06/08 Python
Sanic框架流式传输操作示例
2018/07/18 Python
浅谈python的深浅拷贝以及fromkeys的用法
2019/03/08 Python
详解python中的数据类型和控制流
2019/08/08 Python
Python数据可视化实现漏斗图过程图解
2020/07/20 Python
实例代码讲解Python 线程池
2020/08/24 Python
Python爬虫之App爬虫视频下载的实现
2020/12/08 Python
基于HTML5 FileSystem API的使用介绍
2013/04/24 HTML / CSS
瑜伽国际:Yoga International
2018/04/18 全球购物
Halston Heritage官网:简洁的日装,稍显奢华的晚装
2018/11/20 全球购物
资生堂英国官网:Shiseido英国
2020/12/30 全球购物
旷课检讨书1000字
2014/02/14 职场文书
优秀学生评语大全
2014/04/25 职场文书
放飞梦想演讲稿600字
2014/08/26 职场文书
捐助感谢信
2015/01/22 职场文书
汽车4S店前台接待岗位职责
2015/04/03 职场文书
2016年秋季运动会通讯稿
2015/11/25 职场文书
canvas多重阴影发光效果实现
2021/04/20 Javascript
MySQL修改默认引擎和字符集详情
2021/09/25 MySQL