关于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:风雨欲来 路在何方?
Oct 09 PHP
如何使用PHP获取网络上文件
Oct 09 PHP
php异常处理技术,顶级异常处理器
Jun 13 PHP
php简单浏览目录内容的实现代码
Jun 07 PHP
php常用Stream函数集介绍
Jun 24 PHP
Codeigniter实现多文件上传并创建多个缩略图
Jun 12 PHP
php中error与exception的区别及应用
Jul 28 PHP
PHP 闭包详解及实例代码
Sep 28 PHP
yii2高级应用之自定义组件实现全局使用图片上传功能的方法
Oct 08 PHP
Redis构建分布式锁
Mar 28 PHP
Laravel模糊查询区分大小写的实例
Sep 29 PHP
Yii框架数据库查询、增加、删除操作示例
Oct 14 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分页示例代码
2007/03/19 PHP
19个超实用的PHP代码片段
2014/03/14 PHP
PHP进行批量任务处理不超时的解决方法
2016/07/11 PHP
在PHP语言中使用JSON和将json还原成数组的方法
2016/07/19 PHP
php实现将二维关联数组转换成字符串的方法详解
2017/07/31 PHP
PHP如何解决微信文章图片防盗链
2020/12/09 PHP
javascript 当前日期转化为中文的实现代码
2010/05/13 Javascript
jQuery防止click双击多次提交及传递动态函数或多参数
2014/04/02 Javascript
JS实现文字掉落效果的方法
2015/05/06 Javascript
js实现精美的图片跟随鼠标效果实例
2015/05/16 Javascript
iframe跨域通信封装详解
2015/08/11 Javascript
探讨JavaScript标签位置的存放与功能有无关系
2016/01/15 Javascript
JavaScript编写点击查看大图的页面半透明遮罩层效果实例
2016/05/09 Javascript
Vue表单实例代码
2016/09/05 Javascript
jquery广告无缝轮播实例
2017/01/05 Javascript
js return返回多个值,通过对象的属性访问方法
2017/02/21 Javascript
提高Web性能的前端优化技巧总结
2017/02/27 Javascript
three.js实现3D模型展示的示例代码
2017/12/31 Javascript
node实现登录图片验证码的示例代码
2018/04/20 Javascript
JavaScript递归函数定义与用法实例分析
2019/01/24 Javascript
微信小程序常见页面跳转操作简单示例
2019/05/01 Javascript
js实现简单的打印表格
2020/01/15 Javascript
微信小程序点击生成朋友圈分享图(遇到的坑)
2020/06/17 Javascript
使用python制作游戏下载进度条的代码(程序说明见注释)
2019/10/24 Python
python 实现任务管理清单案例
2020/04/25 Python
详解Python高阶函数
2020/08/15 Python
python中strip(),lstrip(),rstrip()函数的使用讲解
2020/11/17 Python
pycharm Tab键设置成4个空格的操作
2021/02/26 Python
料理师求职信
2014/01/30 职场文书
绿化工程实施方案
2014/03/17 职场文书
学习型党组织建设经验材料
2014/05/26 职场文书
装修公司工程部经理岗位职责
2015/04/09 职场文书
婚宴领导致辞
2015/07/28 职场文书
企业内部管理控制:采购授权审批制度范本
2020/01/19 职场文书
Mysql数据库命令大全
2021/05/26 MySQL
Kubernetes部署实例并配置Deployment、网络映射、副本集
2022/04/01 Servers