关于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执行速度全攻略(下)
Oct 09 PHP
简单的php中文转拼音的实现代码
Feb 11 PHP
php中cookie的使用方法
Mar 29 PHP
ThinkPHP实现事务回滚示例代码
Jun 23 PHP
PHP基于cookie与session统计网站访问量并输出显示的方法
Jan 15 PHP
Zend Framework教程之Application和Bootstrap用法详解
Mar 10 PHP
PHP实现登录搜狐广告获取广告联盟数据的方法【附demo源码】
Oct 14 PHP
PHP开发APP端微信支付功能
Feb 17 PHP
PHP生成腾讯云COS接口需要的请求签名
May 20 PHP
PHP获取MySQL执行sql语句的查询时间方法
Aug 21 PHP
php常用字符串查找函数strstr()与strpos()实例分析
Jun 21 PHP
php源码的使用方法讲解
Sep 26 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/05 新手入门
php实现根据url自动生成缩略图的方法
2014/09/23 PHP
Laravel5中contracts详解
2015/03/02 PHP
PHP遍历目录文件的常用方法小结
2017/02/03 PHP
JavaScript 入门·JavaScript 具有全范围的运算符
2007/10/01 Javascript
Prototype ObjectRange对象学习
2009/07/19 Javascript
自己的js工具_Form 封装
2009/08/21 Javascript
jQuery 使用手册(二)
2009/09/23 Javascript
在次封装easyui-Dialog插件实现代码
2010/11/14 Javascript
鼠标滑在标题上显示图片的JS代码
2013/11/19 Javascript
JQuery.get提交页面不跳转的解决方法
2015/01/13 Javascript
jQuery简单实现验证邮箱格式
2015/07/15 Javascript
详解JavaScript逻辑Not运算符
2015/12/04 Javascript
jQuery代码实现图片墙自动+手动淡入淡出切换效果
2016/05/09 Javascript
工厂模式在JS中的实践
2017/01/18 Javascript
JavaScript函数柯里化原理与用法分析
2017/03/31 Javascript
详解用Node.js实现Restful风格webservice
2017/09/29 Javascript
React组件refs的使用详解
2018/02/09 Javascript
react的hooks的用法详解
2020/10/12 Javascript
python实现的简单抽奖系统实例
2015/05/22 Python
python实现手机通讯录搜索功能
2018/02/22 Python
Python中数组,列表:冒号的灵活用法介绍(np数组,列表倒序)
2018/04/18 Python
python实战之实现excel读取、统计、写入的示例讲解
2018/05/02 Python
对python生成业务报表的实例详解
2019/02/03 Python
python实现诗歌游戏(类继承)
2019/02/26 Python
pyqt 实现在Widgets中显示图片和文字的方法
2019/06/13 Python
python re.sub()替换正则的匹配内容方法
2019/07/22 Python
使用keras实现孪生网络中的权值共享教程
2020/06/11 Python
pycharm Tab键设置成4个空格的操作
2021/02/26 Python
美国鞋类购物网站:Shiekh Shoes
2016/08/21 全球购物
Lulu & Georgia官方网站:购买地毯、家具、抱枕、壁纸、床上用品等
2018/03/19 全球购物
Lucene推荐的分页方式是什么?
2015/12/07 面试题
幼师自我鉴定
2014/02/01 职场文书
2014信息公开实施方案
2014/02/22 职场文书
实习报告评语
2014/04/26 职场文书
Go Plugins插件的实现方式
2021/08/07 Golang