关于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 友好URL的实现(吐血推荐)
Oct 04 PHP
php SQL之where语句生成器
Mar 24 PHP
组合算法的PHP解答方法
Feb 04 PHP
查找mysql字段中固定字符串并替换的几个方法
Sep 23 PHP
PHP命令行脚本接收传入参数的三种方式
Aug 20 PHP
从零开始学YII2框架(一)通过Composer安装Yii2框架
Aug 20 PHP
PHP数组去重比较快的实现方式
Jan 19 PHP
php微信公众平台配置接口开发程序
Sep 22 PHP
form自动提交实例讲解
Jul 10 PHP
yii2局部关闭(开启)csrf的验证的实例代码
Jul 10 PHP
Laravel学习教程之View模块详解
Sep 18 PHP
php弹出提示框的是实例写法
Sep 26 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
SONY ICF-SW55的电路分析
2021/03/02 无线电
php array_map array_multisort 高效处理多维数组排序
2009/06/11 PHP
PHP5中虚函数的实现方法分享
2011/04/20 PHP
利用Ffmpeg获得flv视频缩略图和视频时间的代码
2011/09/15 PHP
WordPress中对访客评论功能的一些优化方法
2015/11/24 PHP
总结PHP中数值计算的注意事项
2016/08/14 PHP
JS获取dom 对象 ajax操作 读写cookie函数
2009/11/18 Javascript
JavaScript移除数组元素减少长度的方法
2013/09/05 Javascript
JS 获取滚动条高度示例代码
2013/10/24 Javascript
Javascript之this关键字深入解析
2013/11/12 Javascript
jquery代码实现多选、不同分享功能
2015/07/31 Javascript
js+css绘制颜色动态变化的圈中圈效果
2016/01/27 Javascript
jQuery EasyUI 入门必看
2016/06/03 Javascript
JS实现的跨浏览器解析XML文件实例
2016/06/21 Javascript
JavaScript实现通过select标签跳转网页的方法
2016/09/29 Javascript
如何防止INPUT按回车自动提交表单FORM
2016/12/06 Javascript
Javascript中的神器——Promise
2017/02/08 Javascript
前端图片懒加载(lazyload)的实现方法(提高用户体验)
2017/08/21 Javascript
JavaScript中防止微信浏览器被整体拖动的方法
2017/08/25 Javascript
Angular搜索 过滤 批量删除 添加 表单验证功能集锦(实例代码)
2017/10/25 Javascript
Vue中$refs的用法详解
2018/06/24 Javascript
微信小程序页面传多个参数跳转页面的实现方法
2019/05/17 Javascript
微信小程序常用的3种提示弹窗实现详解
2019/09/19 Javascript
Python可变参数用法实例分析
2017/04/02 Python
在Python中合并字典模块ChainMap的隐藏坑【推荐】
2019/06/27 Python
对python中 math模块下 atan 和 atan2的区别详解
2020/01/17 Python
python实现简单的tcp 文件下载
2020/09/16 Python
加拿大最大的箱包及旅游配件零售商:Bentley Leathers
2017/07/19 全球购物
设置器与访问器的定义以及各自特点
2016/01/08 面试题
大学生实习自我鉴定
2013/12/11 职场文书
毕业生的自我评价
2013/12/30 职场文书
写求职信要注意什么问题
2014/04/12 职场文书
教师四风自我剖析材料
2014/09/30 职场文书
创业计划书之家教中心
2019/09/25 职场文书
sql server删除前1000行数据的方法实例
2021/08/30 SQL Server
python处理json数据文件
2022/04/11 Python