关于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字符转义相关函数小结(php下的转义字符串)
Apr 12 PHP
PHP生成指定长度随机数最简洁的方法
Jul 14 PHP
php中单个数据库字段多列显示(单字段分页、横向输出)
Jul 28 PHP
thinkphp视图模型查询提示ERR: 1146:Table 'db.pr_order_view' doesn't exist的解决方法
Oct 30 PHP
js+php实现静态页面实时调用用户登陆状态的方法
Jan 04 PHP
YII2.0之Activeform表单组件用法实例
Jan 09 PHP
php图片添加文字水印实现代码
Mar 15 PHP
基于thinkPHP框架实现留言板的方法
Oct 17 PHP
PHP面向对象中new self()与 new static()的区别浅析
Aug 17 PHP
PHP对称加密算法(DES/AES)类的实现代码
Nov 14 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
Feb 23 PHP
浅谈PHP7中的一些小技巧
May 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
德生S2000收音机更换“钕铁硼”全频扬声器
2021/03/02 无线电
phpStudy2016 配置多个域名期间遇到的问题小结
2017/10/19 PHP
Mac下快速搭建PHP开发环境步骤详解
2019/05/05 PHP
PHP中用Trait封装单例模式的实现
2019/12/18 PHP
js弹出层(jQuery插件形式附带reLoad功能)
2013/04/12 Javascript
引入JS文件IE6报语法错误或缺少对象问题的解决方法
2014/01/09 Javascript
JavaScript encodeURI 和encodeURIComponent
2015/12/04 Javascript
老生常谈onBlur事件与onfocus事件(js)
2016/07/09 Javascript
JS针对Array的各种操作汇总
2016/11/29 Javascript
Vue系列:通过vue-router如何传递参数示例
2017/01/16 Javascript
js 实现省市区三级联动菜单效果
2017/02/20 Javascript
jQuery插件select2利用ajax高效查询大数据列表(可搜索、可分页)
2017/05/19 jQuery
js学习总结_基于数据类型检测的四种方式(必看)
2017/07/04 Javascript
JavaScript 自定义事件之我见
2017/09/25 Javascript
详解vue 实例方法和数据
2017/10/23 Javascript
vue解决跨域路由冲突问题思路解析
2017/11/03 Javascript
js将当前时间格式化为 年-月-日 时:分:秒的实现代码
2018/01/20 Javascript
浅析Vue.js 中的条件渲染指令
2018/11/19 Javascript
Python多维/嵌套字典数据无限遍历的实现
2016/11/04 Python
Python之dict(或对象)与json之间的互相转化实例
2018/06/05 Python
python广度优先搜索得到两点间最短路径
2019/01/17 Python
python读取有密码的zip压缩文件实例
2019/02/08 Python
Python一个简单的通信程序(客户端 服务器)
2019/03/06 Python
Python虚拟环境的原理及使用详解
2019/07/02 Python
twilio python自动拨打电话,播放自定义mp3音频的方法
2019/08/08 Python
Python将列表中的元素转化为数字并排序的示例
2019/12/25 Python
Python 实现训练集、测试集随机划分
2020/01/08 Python
Python基于time模块表示时间常用方法
2020/06/18 Python
如何在python中实现线性回归
2020/08/10 Python
Python3.9.0 a1安装pygame出错解决全过程(小结)
2021/02/02 Python
详解Python中openpyxl模块基本用法
2021/02/23 Python
物业招聘计划书
2014/01/10 职场文书
八年级英语教学计划
2015/01/23 职场文书
个人委托书范文
2015/01/28 职场文书
2015年城乡环境综合治理工作总结
2015/07/24 职场文书
工人先锋号事迹材料(2016精选版)
2016/03/01 职场文书