关于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关于array_multisort多维数组排序的使用说明
Jan 04 PHP
一个不易被发现的PHP后门代码解析
Jul 05 PHP
php实现的mongodb操作类实例
Apr 03 PHP
php实现的美国50个州选择列表实例
Apr 20 PHP
php实现的网络相册图片防盗链完美破解方法
Jul 01 PHP
PHP中如何防止外部恶意提交调用ajax接口
Apr 11 PHP
Smarty简单生成表单元素的方法示例
May 23 PHP
php基于curl实现随机ip地址抓取内容的方法
Oct 11 PHP
php动态读取数据清除最右边距的方法
Apr 12 PHP
老生常谈PHP面向对象之命令模式(必看篇)
May 24 PHP
PHP+Mysql+Ajax实现淘宝客服或阿里旺旺聊天功能(前台页面)
Jun 16 PHP
Laravel框架控制器的middleware中间件用法分析
Sep 30 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
锁定年轻人的双倍活力 星巴克推出星倍醇即饮浓咖啡
2021/03/03 咖啡文化
用PHPdig打造属于你自己的Google[图文教程]
2007/02/14 PHP
有关php运算符的知识大全
2011/11/03 PHP
smarty模板引擎使用内建函数foreach循环取出所有数组值的方法
2015/01/22 PHP
jquery api参考 visualjquery 中国线路 速度快
2007/11/30 Javascript
jquery如何改变html标签的样式(两种实现方法)
2013/01/16 Javascript
JavaScript常用全局属性与方法记录积累
2013/07/03 Javascript
jquery创建表格(自动增加表格)代码分享
2013/12/25 Javascript
jquery form 加载数据示例
2014/04/21 Javascript
AngularJS自动表单验证
2016/02/01 Javascript
jQuery中选择器的基础使用教程
2016/05/23 Javascript
轻松掌握jQuery中wrap()与unwrap()函数的用法
2016/05/24 Javascript
js的各种排序算法实现(总结)
2016/07/23 Javascript
原生的强大DOM选择器querySelector介绍
2016/12/21 Javascript
jsTree事件和交互以及插件plugins详解
2017/08/29 Javascript
利用JS测试目标网站的打开响应速度
2017/12/01 Javascript
小程序实现留言板
2018/11/02 Javascript
jquery实现进度条状态展示
2020/03/26 jQuery
JavaScript 实现自己的安卓手机自动化工具脚本(推荐)
2020/05/13 Javascript
Python使用matplotlib填充图形指定区域代码示例
2018/01/16 Python
Go/Python/Erlang编程语言对比分析及示例代码
2018/04/23 Python
Python学习小技巧总结
2018/06/10 Python
Python找出微信上删除你好友的人脚本写法
2018/11/01 Python
python中如何使用分步式进程计算详解
2019/03/22 Python
python交易记录链的实现过程详解
2019/07/03 Python
python误差棒图errorbar()函数实例解析
2020/02/11 Python
德国电子产品购物网站:TechInTheBasket德国
2018/12/07 全球购物
巴西最大的巴士票务门户:Quero Passagem
2020/11/21 全球购物
美国室内盆栽植物购买网站:Plants.com
2020/04/24 全球购物
活动志愿者自荐信
2014/01/27 职场文书
小学数学教学反思
2014/02/02 职场文书
材料成型及控制工程专业求职信
2014/06/19 职场文书
教师一帮一活动总结
2014/07/08 职场文书
优秀家长自荐材料
2014/08/26 职场文书
群众路线学习心得体会范文
2014/11/05 职场文书
出纳2015年度工作总结范文
2015/10/14 职场文书