欢迎来到入门教程网!

PHP编程

当前位置:主页 > 网络编程 > PHP编程 >

关于Yii2框架跑脚本时内存泄漏问题的分析与解决

来源:本站原创|时间:2020-01-11|栏目:PHP编程|点击:

现象

在跑 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编程

下一篇:thinkphp框架类库扩展操作示例

本文标题:关于Yii2框架跑脚本时内存泄漏问题的分析与解决

本文地址:https://www.xiuzhanwang.com/a1/PHPbiancheng/11084.html

网页制作CMS教程网络编程软件编程脚本语言数据库服务器

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:835971066 | 邮箱:835971066#qq.com(#换成@)

Copyright © 2002-2020 脚本教程网 版权所有