关于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实现的功能是显示8条基色色带
Oct 09 PHP
php 文件上传系统手记
Oct 26 PHP
fleaphp常用方法分页之Pager使用方法
Apr 23 PHP
PHP 双链表(SplDoublyLinkedList)简介和使用实例
May 12 PHP
php实现复制移动文件的方法
Jul 29 PHP
Thinkphp+smarty+uploadify实现无刷新上传
Jul 30 PHP
php实现跨域提交form表单的方法【2种方法】
Oct 17 PHP
PHP验证码无法显示的原因及解决办法
Aug 11 PHP
php实现socket推送技术的示例
Dec 20 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
Feb 07 PHP
PHP ADODB生成下拉列表框功能示例
May 29 PHP
PHP实现获取ip地址的5种方法,以及插入用户登录日志操作示例
Feb 28 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实现的购物车类实例
2015/06/17 PHP
thinkPHP多语言切换设置方法详解
2016/11/11 PHP
Yii2语言国际化的配置教程
2018/08/19 PHP
js播放wav文件(源码)
2013/04/22 Javascript
jquery交替变换颜色的三种方法 实例代码
2013/11/19 Javascript
JavaScript实现鼠标点击导航栏变色特效
2017/02/08 Javascript
js 将input框中的输入自动转化成半角大写(税号输入框)
2017/02/16 Javascript
微信小程序实现登录页云层漂浮的动画效果
2017/05/05 Javascript
实例分析JS与Node.js中的事件循环
2017/12/12 Javascript
vue中使用ueditor富文本编辑器
2018/02/08 Javascript
使用vue-cli3新建一个项目并写好基本配置(推荐)
2019/04/24 Javascript
vue中的v-if和v-show的区别详解
2019/09/01 Javascript
uniapp微信小程序实现一个页面多个倒计时
2020/11/01 Javascript
[48:48]完美世界DOTA2联赛PWL S3 Magama vs GXR 第一场 12.19
2020/12/24 DOTA
Python中字符串的常见操作技巧总结
2016/07/28 Python
python库matplotlib绘制坐标图
2019/10/18 Python
Tensorflow中tf.ConfigProto()的用法详解
2020/02/06 Python
Python unittest框架操作实例解析
2020/04/13 Python
详解Python IO口多路复用
2020/06/17 Python
python -v 报错问题的解决方法
2020/09/15 Python
使用CSS3的rem属性制作响应式页面布局的要点解析
2016/05/24 HTML / CSS
CSS3实现swap交换动画
2016/01/19 HTML / CSS
CSS3实现线性渐变用法示例代码详解
2020/08/07 HTML / CSS
Black Halo官方网站:购买连衣裙、礼服和连体裤
2018/06/13 全球购物
Hanro官网:奢华男士和女士内衣、睡衣和家居服
2018/10/25 全球购物
马来西亚在线药房:RoyalePharma
2019/12/01 全球购物
为什么说Ruby是一种真正的面向对象程序设计语言
2012/10/30 面试题
丧事答谢词
2015/01/05 职场文书
安全员岗位职责
2015/02/10 职场文书
春节慰问信范文
2015/02/15 职场文书
2015年副班长工作总结
2015/05/15 职场文书
催款律师函范文
2015/05/27 职场文书
使用Oracle跟踪文件的问题详解
2021/06/28 Oracle
JavaWeb 入门:Hello Servlet
2021/07/16 Java/Android
Python&Matlab实现灰狼优化算法的示例代码
2022/03/21 Python
python使用pycharm安装pyqt5以及相关配置
2022/04/22 Python