誰動了個人內存之PHP內存溢出

今天上午剛到公司,就有同事在公司羣裏反映某個計劃任務出現問題了。我就懷着刨根問底的心,去查看了log。發現挺有意思的一個問題,PHP內存溢出致使腳本執行失敗。那就一塊兒來看個究竟吧!php

  1. 首先查看了計劃任務的Log
    log_error.png數據庫

從報錯信息字面意思能夠看出,容許的134217728 bytes的內存已經用盡,還要試圖分配12961640 bytes內存。
給你(當前腳本)分配的內存你已經用完了,你還想問系統要內存。系統這時想對你說:segmentfault

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

geyou.png

    1. 模擬一下"案發現場"性能

    • 新建一個mem_exhausted.php文件 copy過來一個2.4M的log文件作測試用
      log_size.png測試

    • 寫個簡單的腳本重現"案發現場" 故意分配1M的內存 來讀取2.4M的log
      test_mem_1.png優化

    • 執行腳本,"案發現場"重現
      test_run_res.pngspa

    1. 分析"事故"緣由
      腳本一次性讀取了大量的數據(多是讀的文件,多是讀取的數據庫)code

    以下圖: 往杯子(分配給當前腳本的內存)裏面倒數水(log文件的數據),杯子容量(內存)不夠用
    water_overflow.jpg對象

    1. 解決方案

      1. 既然杯子小 就換個大杯子(增大給腳本分配的內存)治標不治本: ini_set('memory_limit','100M');
        new_1.png

      2. 把水分批次倒入杯子中(循環,分段讀取數據,讀數據庫的話能夠用limit)

    code_1.png

    看看結果

    run_res_new.png

    分段讀取也是能夠解決問題滴

    1. 其餘優化方案

      • 應當儘量減小靜態變量的使用,在須要數據重用時,能夠考慮使用引用(&)。

      • 數據庫操做完成後,要立刻關閉鏈接;

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

      • 用過的變量及時銷燬(unset())掉

      • 可使用memory_get_usage()函數,獲取當前佔用內存 根據當前使用的內存來調整程序

      • unset()函數只能在變量值佔用內存空間超過256字節時纔會釋放內存空間。(PHP內核的gc垃圾回收機制決定)

      • 有當指向該變量的全部變量(如引用變量)都被銷燬後,纔會釋放內存
        (PHP變量底層實現是一個_zval_struct結構體,refcount_gc表示引用計數 is_ref__gc表示是否爲引用)

    -------------------------我是分割線-------------------------

    硬廣時間(對Nginx感興趣的童鞋能夠看下)

    Nginx系列課程索引

    1. 引子: WebServer與PHP通訊姿式
      熟悉瞭解Nginx與PHP是怎麼進行通訊的

    2. 起手式: PHP程序猿應該知道的Nginx (上)
      如何更好的使用Nginx和Nginx配置

    3. 進階式: PHP程序猿應該知道的Nginx (中)
      深刻理解Nginx內核和Nginx運行原理,剖析Nginx高性能的祕密

    4. 實戰篇: PHP程序猿應該知道的Nginx (下)百聞不如一run 一塊兒來開發一個Nginx的拓展

    相關文章
    相關標籤/搜索