关于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通过header实现文本文件下载的代码
Aug 08 PHP
JS与PHP向函数传递可变参数的区别实例代码
May 18 PHP
从手册去理解分析PHP session机制
Jul 17 PHP
PHP的可变变量名的使用方法分享
Feb 05 PHP
php中定时计划任务的实现原理
Jan 08 PHP
php读取mysql的简单实例
Jan 15 PHP
php 使用GD库为页面增加水印示例代码
Mar 24 PHP
php检测数组长度函数sizeof与count用法
Nov 17 PHP
PHP+Mysql+jQuery中国地图区域数据统计实例讲解
Oct 10 PHP
PHP简单的MVC框架实现方法
Dec 01 PHP
ThinkPHP静态缓存简单配置和使用方法详解
Mar 23 PHP
php实现分页功能的详细实例方法
Sep 29 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类(查找/修改)xml文档
2013/03/26 PHP
PHP IE中下载附件问题解决方法
2014/01/07 PHP
修改apache配置文件去除thinkphp url中的index.php
2014/01/17 PHP
PHP_NETWORK_GETADDRESSES: GETADDRINFO FAILED问题解决办法
2014/05/04 PHP
CSDN轮换广告图片轮换效果
2007/03/27 Javascript
ExtJS的FieldSet的column列布局
2009/11/20 Javascript
JS 树形递归实例代码
2010/05/18 Javascript
jquery实现居中弹出层代码
2010/08/25 Javascript
jQuery News Ticker 基于jQuery的即时新闻行情展示插件
2011/11/05 Javascript
屏蔽IE弹出"您查看的网页正在试图关闭窗口,是否关闭此窗口"的方法
2013/12/31 Javascript
jQuery实现数秒后自动提交form的方法
2015/03/05 Javascript
使用JQuery选择HTML遍历函数的方法
2016/09/17 Javascript
JavaScript易错知识点整理
2016/12/05 Javascript
浅谈Vue3.0之前你必须知道的TypeScript实战技巧
2019/09/11 Javascript
vue 动态给每个页面添加title、关键词和描述的方法
2020/08/28 Javascript
微信小程序实现点赞业务
2021/02/10 Javascript
Python语言技巧之三元运算符使用介绍
2013/03/04 Python
Python中不同进制的语法及转换方法分析
2016/07/27 Python
python 自动批量打开网页的示例
2019/02/21 Python
利用python将图片版PDF转文字版PDF
2019/05/03 Python
Python 处理文件的几种方式
2019/08/23 Python
django 数据库连接模块解析及简单长连接改造方法
2019/08/29 Python
python二元表达式用法
2019/12/04 Python
Spartoo比利时:欧洲时尚购物网站
2017/12/06 全球购物
美国滑雪和滑雪板商店:Buckman
2018/03/03 全球购物
资深地理教师自我评价
2013/09/21 职场文书
医学生个人求职信范文
2013/09/24 职场文书
员工自我鉴定
2013/10/09 职场文书
毕业生优秀推荐信
2013/11/26 职场文书
博士研究生自我鉴定范文
2013/12/04 职场文书
信息技术培训感言
2014/03/06 职场文书
《赠汪伦》教学反思
2014/04/12 职场文书
推广普通话演讲稿
2014/05/23 职场文书
上课迟到检讨书300字
2014/10/15 职场文书
Go语言操作数据库及其常规操作的示例代码
2021/04/21 Golang
JS前端轻量fabric.js系列物体基类
2022/08/05 Javascript