記因PHP的記憶體溢出導致的事故之解決

來源:互聯網
上載者:User

標籤:指令碼   對象   讀取資料   code   同事   析構   檔案   有用   str   

如果對您有用記得關注,更多乾貨。

今天上午剛到公司,就有同事在公司群裡反映某個計劃任務出現問題了。我就懷著刨根問底的心,去查看了log。發現挺有意思的一個問題,PHP記憶體溢出導致指令碼執行失敗。那就一起來看個究竟吧!

  1. 首先查看了計劃任務的Log

從報錯資訊字面意思可以看出,允許的134217728 bytes的記憶體已經用盡,還要試圖分配12961640 bytes
記憶體。

給你(當前指令碼)分配的記憶體你已經用完了,你還想問系統要記憶體。系統這時想對你說:

地主家也沒有餘糧啊(借用葛優大爺的一句話)

  1. 類比一下"案發現場"

  • 建立一個mem_exhausted.php檔案 copy過來一個2.4M的log檔案做測試用

  • 寫個簡單的指令碼重現"案發現場" 故意分配1M的記憶體 來讀取2.4M的log

  • 執行指令碼,"案發現場"重現

  1. 分析"事故"原因

    指令碼一次性讀取了大量的資料(可能是讀的檔案,可能是讀取的資料庫)

    如: 往杯子(分配給當前指令碼的記憶體)裡面倒數水(log檔案的資料),杯子容量(記憶體)不夠用

  2. 解決方案

    a. 既然杯子小 就換個大杯子(增大給指令碼分配的記憶體)治標不治本: ini_set(‘memory_limit‘,‘100M‘);

b. 把水分批次倒入杯子中(迴圈,分段讀取資料,讀資料庫的話可以用limit)

看看結果

分段讀取也是可以解決問題滴

  1. 其他最佳化方案

    • 應當儘可能減少靜態變數的使用,在需要資料重用時,可以考慮使用引用(&)。

    • 資料庫操作完成後,要馬上關閉串連;

    • 一個對象使用完,要及時調用解構函式(__destruct())

    • 用過的變數及時銷毀(unset())掉

    • 可以使用memory_get_usage()函數,擷取當前佔用記憶體 根據當前使用的記憶體來調整程式

    • unset()函數只能在變數值佔用記憶體空間超過256位元組時才會釋放記憶體空間。(PHP核心的gc記憶體回收機制決定)

    • 有當指向該變數的所有變數(如引用變數)都被銷毀後,才會釋放記憶體

      (PHP變數底層實現是一個_zval_struct結構體,is_ref__gc表示引用計數 is_ref__gc表示是否為引用)

記因PHP的記憶體溢出導致的事故之解決

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.