• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    关于Yii2框架跑脚本时内存泄漏问题的分析与解决

    现象

    在跑 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 清理到磁盘中

    总结

    以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

    您可能感兴趣的文章:
    • 从零开始学YII2框架(一)通过Composer安装Yii2框架
    • 从零开始学YII2框架(五)快速生成代码工具 Gii 的使用
    • 从零开始学YII2框架(六)高级应用程序模板
    • 从零开始学YII2框架(三)扩展插件yii2-gird
    • 从零开始学YII2框架(二)通过 Composer 安装扩展插件
    • 从零开始学YII2框架(四)扩展插件yii2-kartikgii
    • Yii2框架数据库简单的增删改查语法小结
    • Yii2框架使用计划任务的方法
    上一篇:详解no input file specified 三种解决方法
    下一篇:ThinkPHP5.0框架实现切换数据库的方法分析
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

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