关于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 相关文章推荐
加强版phplib的DB类
Mar 31 PHP
PHP正则的Unknown Modifier错误解决方法
Mar 02 PHP
PHP屏蔽蜘蛛访问代码及常用搜索引擎的HTTP_USER_AGENT
Mar 06 PHP
PHP学习笔记(二) 了解PHP的基本语法以及目录结构
Aug 04 PHP
php将access数据库转换到mysql数据库的方法
Dec 24 PHP
php无限分类使用concat如何实现
Nov 05 PHP
PHP 获取指定地区的天气实例代码
Feb 08 PHP
php实现留言板功能(会话控制)
May 23 PHP
PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
Sep 17 PHP
php数据结构之顺序链表与链式线性表示例
Jan 22 PHP
php设计模式之迭代器模式实例分析【星际争霸游戏案例】
Apr 07 PHP
PHP const定义常量及global定义全局常量实例解析
May 28 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字符串截取中文截取2,单字节截取模式
2007/12/10 PHP
实例讲解PHP页面静态化
2018/02/05 PHP
Laravel框架执行原生SQL语句及使用paginate分页的方法
2018/08/17 PHP
Yii2.0 RESTful API 基础配置教程详解
2018/12/26 PHP
基于jquery实现的表格分页实现代码
2011/06/21 Javascript
原生javascript和jquery判断浏览器版本等信息
2013/07/04 Javascript
js AppendChild与insertBefore用法详细对比
2013/12/16 Javascript
javascript 表格内容排序 简单操作示例代码
2014/01/03 Javascript
javascript处理a标签超链接默认事件的方法
2015/06/29 Javascript
Javascript编写俄罗斯方块思路及实例
2015/07/07 Javascript
AngularJS基础 ng-mouseover 指令简单示例
2016/08/02 Javascript
JavaScript奇技淫巧44招【实用】
2016/12/11 Javascript
AngularJS自定义过滤器用法经典实例总结
2018/05/17 Javascript
layui select获取自定义属性方法
2018/08/15 Javascript
Python基本数据类型详细介绍
2014/03/11 Python
Python的面向对象思想分析
2015/01/14 Python
使用url_helper简化Python中Django框架的url配置教程
2015/05/30 Python
Python中几个比较常见的名词解释
2015/07/04 Python
学习python之编写简单简单连接数据库并执行查询操作
2016/02/27 Python
python使用两种发邮件的方式smtp和outlook示例
2017/06/02 Python
python递归全排列实现方法
2018/08/18 Python
Python中三维坐标空间绘制的实现
2020/09/22 Python
在Python中字典按值排序的实现方法
2020/11/12 Python
next在python中返回迭代器的实例方法
2020/12/15 Python
css3实现背景动态渐变效果
2019/12/10 HTML / CSS
extern在函数声明中是什么意思
2014/01/19 面试题
请解释接口的显式实现有什么意义
2012/05/26 面试题
计算机本科生自荐信
2013/10/15 职场文书
编辑求职信样本
2013/12/16 职场文书
国贸专业大学生职业生涯规划范文
2014/01/10 职场文书
教师中国梦演讲稿
2014/04/23 职场文书
物业管理工作方案
2014/05/10 职场文书
应届大学生自荐书
2014/06/17 职场文书
2014年机关党委工作总结
2014/12/11 职场文书
大学生入党自荐书
2015/03/05 职场文书
2016大学迎新欢迎词
2015/09/29 职场文书