Translate

2015年2月28日 星期六

[PHP] 當你遇到memory size exhausted

[PHP] 當你遇到memory size exhausted

之前寫了一段code,只要一跑,他就會出現以下的這一段

Fatal error:  Allowed memory size of 268435456 bytes exhausted (tried to allocate 36 bytes) in C:\xampp\htdocs\csv2array\csv2Array\csv2DiArray.php on line 56

所以我就用 “memory size””PHP””exhausted”這些關鍵字去查,發現這問題還真的是經常出現呀。




以下就來說明我是怎麼解決問題的,來做個記錄。




出問題的地方在某個迴圈內,且這個迴圈是拿來操作array的。這個array也不過就是讀個400kbcsv檔,大約是10欄,4000筆的資料。

stackoverflow,第一篇出現的解答,叫我們先去調整 php.ini的設定。在php.ini內有個記憶體上限。

memory_limit=256M

這一行,預設為128,可以改為256512等。但我改完後,他只是不斷的在「1xxxxxxx bytes」變為「2xxxxxxxx bytes」直到「5xxxxxxx bytes」為止。我稍微考慮了一下來源檔大小,記憶的限制應該不是原因。

這邊請注意一下,你會在文章中看到有些人會說,一開始下這一行,可以解決一部分人的問題

ini_set('memory_limit', '-1');

上面這一行的意思,就是不設限 memory,所以設定成「-1」。你可以把用盡所有主機的記憶體也沒關係。請注意,這是一個很危險的設定,因為他可能會在日後產生更大更大的問題。雖然這個答案很容易在stackoverflow被推上去,但仔細答案的reply的話,你會發現都會有人提出「這樣做很危險」。

後來再查了stackoverflow其他的文章,有個人遇到的是,他要寫入的array很大,也遇到了memory exhausted的問題。但他的問題在於array的等級把他的memory吃光了。


從這篇文章可以知道,每一個array的變數可能佔48 bytes 56 bytes,而那篇文章的array,應該是11欄,幾萬筆等級的來源。所以光是記憶體就耗了很多的部分在讀檔。

但,這也不是我這段code的問題,我的來源檔規模真的不大,儘104000筆,連記算機都不用按,就知道他不會超過限制。

所以,接下來就是檢查code,我本來的想法是,這是一個二維array,我要遍歷所有的列,讀出[列數][p_code]這個的內容,如果他最後一碼不是T的話,就砍掉。Code如下。

    for ($j =0 ; $j < $countArray; $j++)
    {
    $judge = $targetArray[$j][p_code];
    $judge = substr($judge, -1);
    //$judge = htmlentities($judge);
   
    echo ($judge); // test of the judge ment
    while ($judge != 'T')
        $deleteKey [] = $j;
   
    }
    print_r ($deleteKey);

問題就在這段code,因為這段code出現了不會停的迴圈。改成下列,把$deleteKey[]拿掉,換成echo出所有非T結尾的元素。

    for ($j =0 ; $j < $countArray; $j++)
    {
    $judge = $targetArray[$j][p_code];
    $judge = substr($judge, -1);
    //$judge = htmlentities($judge);
   
    echo ($judge); // test of the judge ment
    while ($judge != 'T')
echo ($targetArray[$j]['p_code']); 
   
    }
    print_r ($deleteKey);

結果就是一切正常,這時候我再重新看網路上這些提問者的內容,除了來源array很大以外,很多出現這個fatal error的原因,就是他們設了迴圈,變數使用$key值找,又同時更改$key值。

最有效率的解法我並不知道,但我可能就會在其他的迴圈來處理 deleteKey這事情,所以第一個array就是單純抓出那些不含T結尾的key值,然後在loop 外使用另一個指令來deleteKey

或許有更有效的方法吧,我稍微試了幾個foreach的指令,雖然還不確定怎麼寫會成功,但感覺如果用foreach來做,就可以做到了。


本人是個PHP新手,新到不能再新的新手,歡迎來信指導。

沒有留言:

張貼留言