溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解決Yii2框架跑腳本時內存泄漏問題

發(fā)布時間:2021-08-05 11:01:57 來源:億速云 閱讀:152 作者:小新 欄目:開發(fā)技術

這篇文章將為大家詳細講解有關如何解決Yii2框架跑腳本時內存泄漏問題,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

現(xiàn)象

在跑 edu_ocr_img 表的歸檔時,每跑幾萬個數(shù)據(jù),都會報一次內存耗盡

PHP Fatal error:  Allowed memory size of 134217728 bytesexhausted (tried toallocate 135168 bytes)

跟蹤代碼發(fā)現(xiàn),是在插入時以下代碼造成的:

EduOCRTaskBackup::getDb()->createCommand()->batchInsert(EduOCRTaskBackup::tableName(), $fields, $data)->execute();

execute 之后會造成使用內存漲上去,并且在之后 unset 所有變量內存也會有一部分不會刪除,直到內存耗盡。

于是跟蹤到 Yii2中execute的具體代碼塊發(fā)現(xiàn)在記錄 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函數(shù)的156行之后會判斷 count($this->messages) >= $this->flushInterval

即:內存中存儲的 message 的條數(shù)要大于等于預設的 $this->flushInterval 才會將內存中的message 刷到磁盤上去。

如果在刷新到磁盤之前就已經將 php.ini 設置的 128M 內存打滿的話,會直接報錯申請內存耗盡。

很多關于 YII2其他原因的內存泄漏的討論
https://github.com/yiisoft/yii2/issues/13256

解決方案

在程序開始時,設置 flushInterval 為一個比較小的值

\Yii::getLogger()->flushInterval = 100; // 設置成一個較小的值

在程序執(zhí)行過程中,每次 execute 之后對內存中的 message 進行 flush

\Yii::getLogger()->flush(true); // 參數(shù)傳 true 表示每次都會將 message 清理到磁盤中

關于“如何解決Yii2框架跑腳本時內存泄漏問題”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI