情況一、程序操作數(shù)據(jù)過(guò)大
情景還原:一次性讀取超過(guò)php可用內(nèi)存上限的數(shù)據(jù)導(dǎo)致內(nèi)存耗盡
<?php ini_set('memory_limit', '128M'); $string = str_pad('1', 128 * 1024 * 1024);
解決辦法:
1、能用錢(qián)解決的問(wèn)題都不是問(wèn)題,如果程序要讀大文件的機(jī)會(huì)不是很多,且上限可預(yù)期,那么通過(guò) ini_set('memory_limit', '1G'); 來(lái)設(shè)置一個(gè)更大的值或者 memory_limit=-1。內(nèi)存管夠的話讓程序一直跑也可以。
2、如果程序需要考慮在小內(nèi)存機(jī)器上也能正常使用,那就需要優(yōu)化程序了。如下,代碼復(fù)雜了很多。
<?php //php7 以下版本通過(guò) composer 引入 paragonie/random_compat ,為了方便來(lái)生成一個(gè)隨機(jī)名稱的臨時(shí)文件 require "vendor/autoload.php"; ini_set('memory_limit', '128M'); //生成臨時(shí)文件存放大字符串 $fileName = 'tmp'.bin2hex(random_bytes(5)).'.txt'; touch($fileName); for ( $i = 0; $i < 128; $i++ ) { $string = str_pad('1', 1 * 1024 * 1024); file_put_contents($fileName, $string, FILE_APPEND); } $handle = fopen($fileName, "r"); for ( $i = 0; $i <= filesize($fileName) / 1 * 1024 * 1024; $i++ ) { //do something $string = fread($handle, 1 * 1024 * 1024); } fclose($handle); unlink($fileName);
情況二、程序操作大數(shù)據(jù)時(shí)產(chǎn)生拷貝
情景還原:執(zhí)行過(guò)程中對(duì)大變量進(jìn)行了復(fù)制,導(dǎo)致內(nèi)存不夠用。
<?php ini_set("memory_limit",'1M'); $string = str_pad('1', 1* 750 *1024); $string2 = $string; $string2 .= '1';
解決辦法:
及早釋放無(wú)用變量,或者以引用的形式操作原始數(shù)據(jù)。
<?php ini_set("memory_limit",'1M'); $string = str_pad('1', 1* 750 *1024); $string2 = $string; unset($string); $string2 .= '1';
情況三、配置不合理系統(tǒng)資源耗盡
情景還原:因配置不合理導(dǎo)致內(nèi)存不夠用,2G 內(nèi)存機(jī)器上設(shè)置最大可以啟動(dòng) 100 個(gè) php-fpm 子進(jìn)程,但實(shí)際啟動(dòng)了 50 個(gè) php-fpm 子進(jìn)程后無(wú)法再啟動(dòng)