关于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 相关文章推荐
Discuz Uchome ajaxpost小技巧
Jan 04 PHP
PHP学习笔记之二 php入门知识
Jan 12 PHP
php购物车实现代码
Oct 10 PHP
php二分查找二种实现示例
Mar 12 PHP
php上传图片之时间戳命名(保存路径)
Aug 15 PHP
php实现递归与无限分类的方法
Feb 16 PHP
PHP随手笔记整理之PHP脚本和JAVA连接mysql数据库
Nov 25 PHP
微信公众号支付之坑:调用支付jsapi缺少参数 timeStamp等错误解决方法
Jan 12 PHP
php 使用html5实现多文件上传实例
Oct 24 PHP
Yii2 hasOne(), hasMany() 实现三表关联的方法(两种)
Feb 15 PHP
php获取目录中所有文件名及判断文件与目录的简单方法
Mar 04 PHP
浅谈PHP各环境下的伪静态配置
Mar 13 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
《心理测量者3》剧场版动画预告
2020/03/02 日漫
基于mysql的论坛(6)
2006/10/09 PHP
zend optimizer在wamp的基础上安装图文教程
2013/10/26 PHP
PHP实现的英文名字全拼随机排号脚本
2014/07/04 PHP
php自定义apk安装包实例
2014/10/20 PHP
Yii2第三方类库插件Imagine的安装和使用
2017/07/06 PHP
thinkPHP中钩子的使用方法实例分析
2017/11/16 PHP
PHP实现基于状态的责任链审批模式详解
2019/05/31 PHP
js关闭当前页面(窗口)的几种方式总结
2013/03/05 Javascript
JQuery操作tr和td内容的方法实例
2013/03/06 Javascript
javascript中数组的冒泡排序使用示例
2013/12/18 Javascript
JS操作iframe里的dom(实例讲解)
2014/01/29 Javascript
学习JavaScript设计模式之模板方法模式
2016/01/20 Javascript
javascript高级选择器querySelector和querySelectorAll全面解析
2016/04/07 Javascript
XMLHttpRequest对象_Ajax异步请求重点(推荐)
2017/09/28 Javascript
在vue中添加Echarts图表的基本使用教程
2017/11/22 Javascript
微信小程序实现手势图案锁屏功能
2018/01/30 Javascript
JavaScript生成指定范围的时间列表
2018/03/19 Javascript
详解Angular中实现自定义组件的双向绑定的两种方法
2018/11/23 Javascript
jQuery实现动态添加和删除input框实例代码
2019/03/26 jQuery
python实现根据月份和日期得到星座的方法
2015/03/27 Python
Python3实现发送QQ邮件功能(附件)
2020/12/23 Python
python 获取list特定元素下标的实例讲解
2018/04/09 Python
python自定义线程池控制线程数量的示例
2019/02/22 Python
python操作cfg配置文件方式
2019/12/22 Python
最小二乘法及其python实现详解
2020/02/24 Python
django实现后台显示媒体文件
2020/04/07 Python
Python装饰器的应用场景代码总结
2020/04/10 Python
python单元测试框架pytest的使用示例
2020/10/07 Python
汽车检测与维修个人求职信
2013/09/24 职场文书
优秀员工年终发言演讲稿
2014/01/01 职场文书
法学专业大学生实习自我鉴定
2014/10/05 职场文书
2015年春节标语口号
2014/12/09 职场文书
SpringCloud Function SpEL注入漏洞分析及环境搭建
2022/04/08 Java/Android
win11系统中dhcp服务异常什么意思? Win11 DHCP服务异常修复方法
2022/04/08 数码科技
MySQL自定义函数及触发器
2022/08/05 MySQL