关于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 相关文章推荐
JAVA/JSP学习系列之四
Oct 09 PHP
PHP中return 和 exit 、break和contiue 区别与用法
Apr 09 PHP
php单例模式实现(对象只被创建一次)
Dec 05 PHP
ThinkPHP采用原生query实现关联查询left join实例
Dec 02 PHP
PHP树的深度编历生成迷宫及A*自动寻路算法实例分析
Mar 10 PHP
PHP 9 大缓存技术总结
Sep 17 PHP
网页的分页下标生成代码(PHP后端方法)
Feb 03 PHP
利用PHP自动生成印有用户信息的名片
Aug 01 PHP
php使用curl详细解析及问题汇总
Aug 11 PHP
PHP xpath()函数讲解
Feb 11 PHP
Yii框架中使用PHPExcel的方法分析
Jul 25 PHP
PHP读取XML文件的方法实例总结【DOMDocument及simplexml方法】
Sep 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
从康盛产品(discuz)提取出来的模板类
2011/06/28 PHP
smarty模板中使用get、post、request、cookies、session变量的方法
2014/04/24 PHP
php简单统计在线人数的方法
2016/05/10 PHP
快速解决PHP调用Word组件DCOM权限的问题
2017/12/27 PHP
基于JavaScript实现继承机制之调用call()与apply()的方法详解
2013/05/07 Javascript
jquery实现商品拖动选择效果代码(自写)
2013/05/28 Javascript
让元素在网页中可拖动示例代码
2013/08/13 Javascript
javascript模拟地球旋转效果代码实例
2013/12/02 Javascript
jquery数组之存放checkbox全选值示例代码
2013/12/20 Javascript
js中传递特殊字符(+,&)的方法
2014/01/16 Javascript
JavaScript原型链示例分享
2014/01/26 Javascript
Angularjs 基础入门
2014/12/26 Javascript
jquery实现炫酷的叠加层自动切换特效
2015/02/01 Javascript
jquery中trigger()无法触发hover事件的解决方法
2015/05/07 Javascript
JS或jQuery获取ASP.NET服务器控件ID的方法
2015/06/08 Javascript
yii form 表单提交之前JS在提交按钮的验证方法
2017/03/15 Javascript
Angular2下使用pdf插件的方法详解
2017/04/29 Javascript
利用node.js如何搭建一个简易的即时响应服务器
2017/05/28 Javascript
Node.js中环境变量process.env的一些事详解
2017/10/26 Javascript
node.js基础知识小结
2018/02/26 Javascript
Js中使用正则表达式验证输入是否有特殊字符
2018/09/07 Javascript
vue组件通信传值操作示例
2019/01/08 Javascript
atom-design(Vue.js移动端组件库)手势组件使用教程
2019/05/16 Javascript
python代码检查工具pylint 让你的python更规范
2012/09/05 Python
Python安装第三方库及常见问题处理方法汇总
2016/09/13 Python
python 发送和接收ActiveMQ消息的实例
2019/01/30 Python
django中上传图片分页三级联动效果的实现代码
2019/08/30 Python
基于python实现蓝牙通信代码实例
2019/11/19 Python
python读写文件write和flush的实现方式
2020/02/21 Python
3种方式实现瀑布流布局小结
2019/09/05 HTML / CSS
美国名牌手表折扣网站:Jomashop
2020/05/22 全球购物
会计实习生工作总结的自我评价
2013/10/07 职场文书
竞争上岗实施方案
2014/03/21 职场文书
研究生导师推荐信
2014/09/06 职场文书
同意转租证明
2015/06/24 职场文书
python b站视频下载的五种版本
2021/05/27 Python