今天上午剛到公司,就有同事在公司羣裏反映某個計劃任務出現問題了。我就懷着刨根問底的心,去查看了log。發現挺有意思的一個問題,PHP內存溢出致使腳本執行失敗。那就一塊兒來看個究竟吧!php
首先查看了計劃任務的Log數據庫
從報錯信息字面意思能夠看出,容許的134217728 bytes
的內存已經用盡,還要試圖分配12961640 bytes
內存。
給你(當前腳本)分配的內存你已經用完了,你還想問系統要內存。系統這時想對你說:segmentfault
地主家也沒有餘糧啊(借用葛優大爺的一句話)函數
模擬一下"案發現場"性能
新建一個mem_exhausted.php文件 copy過來一個2.4M的log文件作測試用測試
寫個簡單的腳本重現"案發現場" 故意分配1M的內存 來讀取2.4M的log優化
執行腳本,"案發現場"重現spa
分析"事故"緣由
腳本一次性讀取了大量的數據(多是讀的文件,多是讀取的數據庫)code
以下圖: 往杯子(分配給當前腳本的內存)裏面倒數水(log文件的數據),杯子容量(內存)不夠用對象
解決方案
既然杯子小 就換個大杯子(增大給腳本分配的內存)治標不治本: ini_set('memory_limit','100M');
把水分批次倒入杯子中(循環,分段讀取數據,讀數據庫的話能夠用limit)
看看結果
分段讀取也是能夠解決問題滴
其餘優化方案
應當儘量減小靜態變量的使用,在須要數據重用時,能夠考慮使用引用(&)。
數據庫操做完成後,要立刻關閉鏈接;
一個對象使用完,要及時調用析構函數(__destruct())
用過的變量及時銷燬(unset())掉
可使用memory_get_usage()函數,獲取當前佔用內存 根據當前使用的內存來調整程序
unset()函數只能在變量值佔用內存空間超過256字節時纔會釋放內存空間。(PHP內核的gc垃圾回收機制決定)
有當指向該變量的全部變量(如引用變量)都被銷燬後,纔會釋放內存
(PHP變量底層實現是一個_zval_struct結構體,refcount_gc表示引用計數 is_ref__gc表示是否爲引用)
-------------------------我是分割線-------------------------
Nginx系列課程索引
引子: WebServer與PHP通訊姿式
熟悉瞭解Nginx與PHP是怎麼進行通訊的
起手式: PHP程序猿應該知道的Nginx (上)
如何更好的使用Nginx和Nginx配置
進階式: PHP程序猿應該知道的Nginx (中)
深刻理解Nginx內核和Nginx運行原理,剖析Nginx高性能的祕密
實戰篇: PHP程序猿應該知道的Nginx (下)百聞不如一run 一塊兒來開發一個Nginx的拓展