关于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 相关文章推荐
main.php
Dec 09 PHP
php设计模式之命令模式的应用详解
May 21 PHP
PHP 使用header函数设置HTTP头的示例解析 表头
Jun 17 PHP
xss防御之php利用httponly防xss攻击
Mar 21 PHP
php生成随机数的三种方法
Sep 10 PHP
php修改指定文件后缀的方法
Sep 11 PHP
PHP实现自动登入google play下载app report的方法
Sep 23 PHP
PHP移动文件指针ftell()、fseek()、rewind()函数总结
Nov 18 PHP
php实现的一个简单json rpc框架实例
Mar 30 PHP
thinkPHP3.1验证码的简单实现方法
Apr 22 PHP
php pdo操作数据库示例
Mar 10 PHP
laravel + vue实现的数据统计绘图(今天、7天、30天数据)
Jul 31 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带抄送和密件抄送的邮件发送方法
2015/03/20 PHP
编写PHP程序检查字符串中的中文字符个数的实例分享
2016/03/17 PHP
php通过PHPExcel导入Excel表格到MySQL数据库的简单实例
2016/10/29 PHP
PHP与JavaScript针对Cookie的读写、交互操作方法详解
2017/08/07 PHP
JavaScript Tips 使用DocumentFragment加快DOM渲染速度
2010/06/28 Javascript
js注意img图片的onerror事件的分析
2011/01/01 Javascript
Ext.get() 和 Ext.query()组合使用实现最灵活的取元素方式
2011/09/26 Javascript
js给onclick事件赋值,动态传参数实例解说
2013/03/28 Javascript
ExtJS4中使用mixins实现多继承示例
2013/12/03 Javascript
javascript实现在某个元素上阻止鼠标右键事件的方法和实例
2014/08/12 Javascript
js中匿名函数的创建与调用方法分析
2014/12/19 Javascript
浅谈angular.js中实现双向绑定的方法$watch $digest $apply
2015/10/14 Javascript
jquery获取img的src值的简单实例
2016/05/17 Javascript
JavaScript 是什么意思
2016/09/22 Javascript
js实现点击图片自动提交action的简单方法
2016/10/16 Javascript
微信小程序 判断手机号的实现代码
2017/04/19 Javascript
vue组件中使用iframe元素的示例代码
2017/12/13 Javascript
使用jQuery 操作table 完成单元格合并的实例
2017/12/27 jQuery
jquery 回调操作实例分析【回调成功与回调失败的情况】
2019/09/27 jQuery
vue vantUI实现文件(图片、文档、视频、音频)上传(多文件)
2019/10/15 Javascript
vue实现购物车加减
2020/05/30 Javascript
JS时间戳与日期格式互相转换的简单方法示例
2021/01/30 Javascript
微信小程序对图片进行canvas压缩的方法示例详解
2020/11/12 Javascript
[39:07]LGD vs VP 2018国际邀请赛淘汰赛BO3 第二场 8.21
2018/08/22 DOTA
[54:57]DOTA2-DPC中国联赛定级赛 Aster vs DLG BO3第二场 1月8日
2021/03/11 DOTA
Python实现正则表达式匹配任意的邮箱方法
2018/12/20 Python
Python虚拟环境的原理及使用详解
2019/07/02 Python
Python之qq自动发消息的示例代码
2021/02/18 Python
新学期红领巾广播稿
2014/01/14 职场文书
小学后勤管理制度
2014/01/14 职场文书
珍惜资源的建议书
2014/08/26 职场文书
个人租房协议书样本
2014/10/01 职场文书
2014年纳税评估工作总结
2014/12/23 职场文书
小学生差生评语
2014/12/29 职场文书
基层党建工作简报
2015/07/21 职场文书
win11高清晰音频管理器在哪里?win11找不到高清晰音频管理器解决办法
2022/04/08 数码科技