关于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与XML联手进行网站编程代码实例
Jul 10 PHP
PHP 采集获取指定网址的内容
Jan 05 PHP
整理的9个实用的PHP库简介和下载
Nov 09 PHP
PHP文件上传原理简单分析
May 29 PHP
有关PHP性能优化的介绍
Jun 20 PHP
解析PHP的session过期设置
Jun 29 PHP
zf框架的Filter过滤器使用示例
Mar 13 PHP
php获取textarea的值并处理回车换行的方法
Oct 20 PHP
php绘制一条直线的方法
Jan 24 PHP
PHP date函数常用时间处理方法
May 11 PHP
php微信开发之关键词回复功能
Jun 13 PHP
PHP实现SMTP邮件的发送实例
Sep 27 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中获取指定IP的物理地址的代码(正则表达式)
2011/06/23 PHP
PHP打印输出函数汇总
2016/08/28 PHP
thinkphp ajaxfileupload实现异步上传图片的示例
2017/08/28 PHP
再谈javascript面向对象编程
2012/03/18 Javascript
js读写(删除)Cookie实例详解
2013/04/17 Javascript
一个JavaScript变量声明的知识点
2013/10/28 Javascript
推荐10 款 SVG 动画的 JavaScript 库
2015/03/24 Javascript
jquery小火箭返回顶部代码分享
2015/08/19 Javascript
跟我学习javascript的最新标准ES6
2015/11/20 Javascript
js获取上传文件的绝对路径实现方法
2016/08/02 Javascript
用jQuery实现优酷首页轮播图
2017/01/09 Javascript
使用requirejs模块化开发多页面一个入口js的使用方式
2017/06/14 Javascript
EasyUI的TreeGrid的过滤功能的解决思路
2017/08/08 Javascript
使用yeoman构建angular应用的方法
2017/08/14 Javascript
AngularJS实时获取并显示密码的方法
2018/02/06 Javascript
vue中的inject学习教程
2019/04/24 Javascript
超详细的5个Shell脚本实例分享(值得收藏)
2019/08/15 Javascript
js实现简单的日历显示效果函数示例
2019/11/25 Javascript
前端开发之便利店收银系统代码
2019/12/27 Javascript
vue制作抓娃娃机的示例代码
2020/04/17 Javascript
[00:32]2018DOTA2亚洲邀请赛EG出场
2018/04/03 DOTA
Gauss-Seidel迭代算法的Python实现详解
2019/06/29 Python
Python-Seaborn热图绘制的实现方法
2019/07/15 Python
Python多线程模块Threading用法示例小结
2019/11/09 Python
np.random.seed() 的使用详解
2020/01/14 Python
Pytorch之Tensor和Numpy之间的转换的实现方法
2020/09/03 Python
企业面试题试卷附带答案
2015/12/20 面试题
安全检查与奖惩制度
2014/01/23 职场文书
《狼和小羊》教学反思
2014/04/20 职场文书
党政领导班子四风问题对照检查材料思想汇报
2014/10/02 职场文书
劳动争议和解协议书范本
2014/11/20 职场文书
校园环境卫生倡议书
2015/04/29 职场文书
有关朝花夕拾的读书笔记
2015/06/29 职场文书
化验室安全管理制度
2015/08/06 职场文书
Apache Calcite 实现方言转换的代码
2021/04/24 Servers
CentOS7和8下安装Maven3.8.4
2022/04/07 Servers