主頁 > 知識(shí)庫 > 關(guān)于Yii2框架跑腳本時(shí)內(nèi)存泄漏問題的分析與解決

關(guān)于Yii2框架跑腳本時(shí)內(nèi)存泄漏問題的分析與解決

熱門標(biāo)簽:服務(wù)器配置 Linux服務(wù)器 科大訊飛語音識(shí)別系統(tǒng) Mysql連接數(shù)設(shè)置 阿里云 電子圍欄 團(tuán)購網(wǎng)站 銀行業(yè)務(wù)

現(xiàn)象

在跑 edu_ocr_img 表的歸檔時(shí),每跑幾萬個(gè)數(shù)據(jù),都會(huì)報(bào)一次內(nèi)存耗盡

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

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

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

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

于是跟蹤到 Yii2中execute的具體代碼塊發(fā)現(xiàn)在記錄 log 的時(shí)候會(huì)將使用很高的內(nèi)存,分析代碼之后得出造成泄漏的代碼塊如下:

造成泄漏的代碼塊

/**
 * 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;
    }
   }
  }
 }
 
 // 這里是造成內(nèi)存的罪魁禍?zhǔn)?
 $this->messages[] = [$message, $level, $category, $time, $traces];
 if ($this->flushInterval > 0  count($this->messages) >= $this->flushInterval) {
  $this->flush();
 }
}

造成內(nèi)存泄漏的原因分析

在 Yii2框架中的 vendor/yiisoft/yii2/log/Logger.php:156 log函數(shù)的156行之后會(huì)判斷 count($this->messages) >= $this->flushInterval

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

如果在刷新到磁盤之前就已經(jīng)將 php.ini 設(shè)置的 128M 內(nèi)存打滿的話,會(huì)直接報(bào)錯(cuò)申請(qǐng)內(nèi)存耗盡。

很多關(guān)于 YII2其他原因的內(nèi)存泄漏的討論
https://github.com/yiisoft/yii2/issues/13256

解決方案

在程序開始時(shí),設(shè)置 flushInterval 為一個(gè)比較小的值

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

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

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

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

您可能感興趣的文章:
  • 從零開始學(xué)YII2框架(一)通過Composer安裝Yii2框架
  • 從零開始學(xué)YII2框架(五)快速生成代碼工具 Gii 的使用
  • 從零開始學(xué)YII2框架(六)高級(jí)應(yīng)用程序模板
  • 從零開始學(xué)YII2框架(三)擴(kuò)展插件yii2-gird
  • 從零開始學(xué)YII2框架(二)通過 Composer 安裝擴(kuò)展插件
  • 從零開始學(xué)YII2框架(四)擴(kuò)展插件yii2-kartikgii
  • Yii2框架數(shù)據(jù)庫簡單的增刪改查語法小結(jié)
  • Yii2框架使用計(jì)劃任務(wù)的方法

標(biāo)簽:江蘇 大理 棗莊 衡水 蚌埠 萍鄉(xiāng) 廣元 衢州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《關(guān)于Yii2框架跑腳本時(shí)內(nèi)存泄漏問題的分析與解決》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266