关于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 存取 MySQL 数据库的一个例子
Oct 09 PHP
一个可以删除字符串中HTML标记的PHP函数
Oct 09 PHP
Base64在线编码解码实现代码 演示与下载
Jan 08 PHP
php中用socket模拟http中post或者get提交数据的示例代码
Aug 08 PHP
php中将数组转成字符串并保存到数据库中的函数代码
Sep 29 PHP
thinkphp实现数组分页示例
Apr 13 PHP
PHP中file_get_contents高?用法实例
Sep 24 PHP
php简单实现多字节字符串翻转的方法
Mar 31 PHP
PHP中Session和Cookie是如何操作的
Oct 10 PHP
thinkphp实现把数据库中的列的值存到下拉框中的方法
Jan 20 PHP
php数组函数array_push()、array_pop()及array_shift()简单用法示例
Jan 26 PHP
goto语法在PHP中的使用教程
Sep 17 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
Windows下的PHP安装pear教程
2014/10/24 PHP
CI框架入门示例之数据库取数据完整实现方法
2014/11/05 PHP
PHP实现支持SSL连接的SMTP邮件发送类
2015/03/05 PHP
PHP数组去重比较快的实现方式
2016/01/19 PHP
Laravel相关的一些故障解决
2020/08/19 PHP
JavaScript 替换Html标签实现代码
2009/10/14 Javascript
jQuery + Flex 通过拖拽方式动态改变图片的代码
2011/08/03 Javascript
JavaScript中this的使用详解
2013/11/08 Javascript
jQuery实现鼠标可拖动调整表格列宽度
2014/05/26 Javascript
用js提交表单解决一个页面有多个提交按钮的问题
2014/09/01 Javascript
JS实现定时自动关闭DIV层提示框的方法
2015/05/11 Javascript
jQuery 1.9.1源码分析系列(十三)之位置大小操作
2015/12/02 Javascript
简单实现js页面切换功能
2021/01/10 Javascript
jQuery如何封装输入框插件
2016/08/19 Javascript
JS获取多维数组中相同键的值实现方法示例
2017/01/06 Javascript
jQuery简单绑定单个事件的方法示例
2017/06/10 jQuery
详解使用Visual Studio Code对Node.js进行断点调试
2017/09/14 Javascript
vue 音乐App QQ音乐搜索列表最新接口跨域设置方法
2018/09/25 Javascript
jQuery实现每日秒杀商品倒计时功能
2019/09/06 jQuery
JS addEventListener()和attachEvent()方法实现注册事件
2021/01/11 Javascript
用python分割TXT文件成4K的TXT文件
2009/05/23 Python
Python实现的数据结构与算法之快速排序详解
2015/04/22 Python
Python对列表排序的方法实例分析
2015/05/16 Python
详解Python多线程
2016/11/14 Python
Python之日期与时间处理模块(date和datetime)
2017/02/16 Python
利用python实现对web服务器的目录探测的方法
2019/02/26 Python
PyCharm搭建Spark开发环境实现第一个pyspark程序
2019/06/13 Python
django的auth认证,authenticate和装饰器功能详解
2019/07/25 Python
python去除删除数据中\u0000\u0001等unicode字符串的代码
2020/03/06 Python
Hunkemöller西班牙:欧洲最大的内衣连锁店
2018/08/15 全球购物
材料工程专业毕业生求职信
2014/03/04 职场文书
学生期末评语大全
2014/04/30 职场文书
九寨沟导游词
2015/02/02 职场文书
2015年乡镇科普工作总结
2015/05/13 职场文书
勇敢的心观后感
2015/06/09 职场文书
毕业生就业推荐表自我鉴定
2019/06/20 职场文书