关于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 相关文章推荐
截获网站title标签之家内容的例子
Oct 09 PHP
apache2.2.4+mysql5.0.77+php5.2.8安装精简
Apr 29 PHP
解析PHP 5.5 新特性
Jul 02 PHP
服务器变量 $_SERVER 的深入解析
Jul 02 PHP
PHP类继承 extends使用介绍
Jan 14 PHP
通过curl模拟post和get方式提交的表单类
Apr 23 PHP
php通过获取头信息判断图片类型的方法
Jun 26 PHP
PHP 微信扫码支付源代码(推荐)
Nov 03 PHP
Yii框架扩展CGridView增加导出CSV功能的方法
May 24 PHP
Redis在Laravel项目中的应用实例详解
Aug 11 PHP
PHP递归实现汉诺塔问题的方法示例
Nov 25 PHP
YII2框架中日志的配置与使用方法实例分析
Mar 18 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 && 逻辑与运算符使用说明
2010/03/04 PHP
PHP实现异步调用方法研究与分享
2011/10/27 PHP
PHP使用Face++接口开发微信公众平台人脸识别系统的方法
2015/04/17 PHP
PHP获取Exif缩略图的方法
2015/07/13 PHP
PHP实现通过文本文件统计页面访问量功能示例
2019/02/13 PHP
用javascript操作xml
2006/11/04 Javascript
用js实现多域名不同文件的调用方法
2007/01/12 Javascript
一个可以显示阴历的JS代码
2007/03/05 Javascript
jQuery 剧场版 你必须知道的javascript
2009/05/27 Javascript
浅析JavaScript中的同名标识符优先级
2013/12/06 Javascript
alert和confirm功能介绍
2014/05/21 Javascript
jQuery对象初始化的传参方式
2015/02/26 Javascript
jquery实现可横向和竖向展开的动态下滑菜单效果
2015/08/24 Javascript
用js控件div的滚动条,让它在内容更新时自动滚到底部的实现方法
2016/10/27 Javascript
JS实现的简单轮播图运动效果示例
2016/12/22 Javascript
JavaScript轻松创建级联函数的方法示例
2017/02/10 Javascript
深入理解AngularJS中的ng-bind-html指令
2017/03/27 Javascript
详解angularjs利用ui-route异步加载组件
2017/05/21 Javascript
Angularjs 实现动态添加控件功能
2017/05/25 Javascript
vue+vant实现商品列表批量倒计时功能
2020/01/13 Javascript
JavaScript数组常用的增删改查与其他属性详解
2020/10/13 Javascript
python 连接sqlite及简单操作
2017/06/30 Python
Python模块结构与布局操作方法实例分析
2017/07/24 Python
python机器学习实战之最近邻kNN分类器
2017/12/20 Python
详解TensorFlow在windows上安装与简单示例
2018/03/05 Python
python tkinter 设置窗口大小不可缩放实例
2020/03/04 Python
python如何调用字典的key
2020/05/25 Python
做一个能自适应高度的textarea的示例代码
2019/09/06 HTML / CSS
L’AGENCE官网:加州女装品牌
2018/06/03 全球购物
联想英国官网:Lenovo英国
2019/07/17 全球购物
给定一个时间点,希望得到其他时间点
2013/11/07 面试题
校园餐饮创业计划书
2014/01/10 职场文书
2014社区三八妇女节活动总结
2014/03/01 职场文书
党建示范点实施方案
2014/03/12 职场文书
导游词之山海关
2019/12/10 职场文书
Python实现为PDF去除水印的示例代码
2022/04/03 Python