关于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
PHP一些有意思的小区别
Dec 06 PHP
理解PHP5中static和const关键字的区别
Mar 19 PHP
php实现单链表的实例代码
Mar 22 PHP
PHP中的Memcache详解
Apr 05 PHP
PHP5中实现多态的两种方法实例分享
Apr 21 PHP
使用配置类定义Codeigniter全局变量
Jun 12 PHP
PHP采用自定义函数实现遍历目录下所有文件的方法
Aug 19 PHP
在Linux系统的服务器上隐藏PHP版本号的方法
Jun 06 PHP
PHP+JS实现大规模数据提交的方法
Jul 02 PHP
在Laravel中实现使用AJAX动态刷新部分页面
Oct 15 PHP
php实现JWT(json web token)鉴权实例详解
Nov 05 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模板Smarty的初级使用方法以及心得分享
2013/06/21 PHP
Yii使用技巧大汇总
2015/12/29 PHP
RR vs IO BO3 第二场2.13
2021/03/10 DOTA
JavaScript 实现模态对话框 源代码大全
2009/05/02 Javascript
简洁Ajax函数处理(示例代码)
2013/11/15 Javascript
怎么选择Javascript框架(Javascript Framework)
2013/11/22 Javascript
JavaScript中数组的合并以及排序实现示例
2015/10/24 Javascript
限制文本框只能输入数字||只能是数字和小数点||只能是整数和浮点数
2016/05/27 Javascript
jQuery图片左右滚动代码 有左右按钮实例
2016/06/20 Javascript
动态加载JavaScript文件的3种方式
2018/05/05 Javascript
vue.js绑定事件监听器示例【基于v-on事件绑定】
2018/07/07 Javascript
微信小程序实现两个页面传值的方法分析
2018/12/11 Javascript
记录一次开发微信网页分享的步骤
2019/05/07 Javascript
jquery html添加元素/删除元素操作实例详解
2020/05/20 jQuery
JS实现前端路由功能示例【原生路由】
2020/05/29 Javascript
vue全局使用axios的操作
2020/09/08 Javascript
关于vue 项目中浏览器跨域的配置问题
2020/11/10 Javascript
[01:02:48]2018DOTA2亚洲邀请赛 4.1 小组赛 A组 LGD vs OG
2018/04/02 DOTA
[56:46]2018DOTA2亚洲邀请赛 3.31 小组赛 B组 VP vs Effect
2018/04/01 DOTA
Python爬虫PyQuery库基本用法入门教程
2018/08/04 Python
python爬虫 爬取58同城上所有城市的租房信息详解
2019/07/30 Python
python实现复制大量文件功能
2019/08/31 Python
Python字典中的值为列表或字典的构造实例
2019/12/16 Python
PyCharm上安装Package的实现(以pandas为例)
2020/09/18 Python
HTML5中外部浏览器唤起微信分享
2020/01/02 HTML / CSS
详解HTML5 Canvas标签及基本使用
2020/01/10 HTML / CSS
Fox Racing官方网站:越野摩托车和山地自行车装备和服装
2019/12/23 全球购物
美国价格实惠的在线眼镜网站:Zeelool
2020/12/25 全球购物
英语系本科生个人求职信
2013/09/21 职场文书
数控技校生自我鉴定
2014/04/19 职场文书
法定代表人证明书
2014/11/28 职场文书
培训师岗位职责
2015/02/14 职场文书
三八妇女节慰问信
2015/02/14 职场文书
2015年学生会部门工作总结
2015/04/21 职场文书
有关三国演义的读书笔记
2015/06/25 职场文书
MySQL事务操作的四大特性以及并发事务问题
2022/04/12 MySQL