一、前言
這篇文章其實是上篇文章的記憶體優化部分。部落客的php程式在執行的時候,報錯:
Out of memory (allocated 364904448) (tried to allocate 262144 bytes)
也就是傳統的記憶體不足報錯,問題是我本地設定的記憶體已經是1280M了,簡直不能忍。是以這裡一步步的看一篇代碼,記錄一下需要優化的地方,主要是針對數組的
二、優化前準備
1、首先是檢視php的目前記憶體設定
windows: 打開php.ini,搜尋:memory_limit ,一般設定為128M夠用
linux: 執行“php -i | grep Loaded Configuration File”來找到對應的配置檔案。
注: 這個指令是搜尋php程式的配置檔案所在位置,打開phpinfo,可以看到有個Loaded Configuration File 選項,對應
的就是php.ini檔案的位置
2、一個php數組能占用多大記憶體
參考:https://blog.csdn.net/hguisu/article/details/7376705
通過大佬的分析,我們可以知道:
(1)php對于數組的利用效率很低,一個在C語言裡面100M 記憶體的數組,在PHP裡面就要1G;
(2)php空數組都要14(zval) + 39(HashTable) + 33(arBuckets) = 86 個位元組
(3)php檢視記憶體方法:memory_get_usage() ,具體用法: echo memory_get_usage(); 即可,部落客通過該方法,确認記憶體瓶頸出在了數組部分
三、優化過程
1、代碼備援
$arr = [];
foreach($response['hits']['hits'] as $v)
{
$arr[] = $v['_source'];
}
unset($v);
//加上原來沒有的一些字段,篩選掉沒有pixel的資料
foreach($arr as $key=>$v){
if(!array_key_exists('pixel.uuid',$v)){
unset($arr[$key]);
}
優化點評: 這裡的$arr是完全不必要的,既然下面還是要篩選,那麼直接循環下面的那個$response['hits']['hits']即可,如果$arr是很大的數組,那麼在指派之後,又要開辟一塊記憶體給它。是以要盡量避免這種情況的發生。
2、數組指派給另一個空數組
if(count($this->arrEsIndex) > 0){
unset($this->arrEsIndex);
$this->arrEsIndex = $arr;
}else{
}
優化點評: 像這種數組指派操作盡量少做。因為把 $arr指派給$this->arrEsindex之後,如果$this->arrEsIndex的值改變了,那麼使用的記憶體相當于翻倍的效果。其次是指派之後,這個$arr其實已經沒用了,但是由于咱們沒有進行unset,是以就造成這個$arr還在占用記憶體的情況。建議是unset($arr),也就是unset掉咱們不用的那些數組。
正常的指派是不會發生記憶體改變的,但是當指派的新數組發生改動的時候,php就會新開辟記憶體給新的數組,這裡會造成無謂的記憶體消耗。最好是不要直接這樣指派,如果非指派不可的話,記得加上‘&’符号,通過傳引用直接傳遞位址給新數組,這樣當新數組發生變化的時候,更改的還是原來的那塊記憶體。
3、把數組傳參給函數
$this->getScrollData($repos);
優化點評: 這裡的$repos是一個數組。正常來說,傳值傳數組也是可以的,但是如果這個數組裡面的元素是萬級别的,那麼
這個操作也是非常耗記憶體的。在php程式中,隻要傳參,參數都會拷貝一份,是以值越大,耗的記憶體越大。針對這種情況,
建議是在類裡面定義全局變量,然後函數體裡面通過:$this->repos來操作這個數組。也可以考慮使用傳引用的方式,因為使用&的話,傳遞過去的事一個記憶體位址,位數并不大。
4、把判斷條件寫在循環外面,避免每次都要循環的情況
foreach($this->arrEsIndex as $k=>&$v) {
if (!empty($this->search_abtest_key) && $this->search_abtest_key != "is_50mclient") {
$v[$this->search_abtest_key] = 0;
優化點評: 這個操作也有問題,如果if條件滿足的話還好。如果If條件不滿足的話,在業務層面根本就不需要進行這部分操作。但是由于咱們的forteach循環在最外面,是以照樣會循環一下數組。問題這是個很大的數組,消耗的記憶體也很可觀。
5、unset掉比較大的變量
針對一些比較大的變量(最好大于256位元組),如果隻是臨時使用的話,使用完之後記得unset()掉。如果對變量進行'&'傳引用的話,會增加該記憶體的引用計數,直接unset()變量并不會立馬釋放變量,因為unset隻是斷開一個變量到一塊記憶體區域的連接配接,同時将該記憶體區域的引用計數-1,如果把引用指派的那個變量也unset()掉才會立馬釋放記憶體。
6、單個大數組消耗太多記憶體的解決方案
參考:http://www.phpzy.com/php/16958.html
通過存入字元串的方式優化,使用數組的時候就再把字元串轉化為數組
7、循環操作DB
這個問題是老生常談了,部落客代碼裡沒有出現這個情況,不過大家還是注意下比較好。循環不斷操作DB,非常影響程式性能。
四、總結
以上的優化部分也是部落客一步步看着代碼慢慢優化的,相對而言都是一些比較淺層面的優化。不過這些問題也告訴我們,寫完代碼記得要再看一遍,如果可以的話,在開始編寫代碼的時候就要注意性能問題。最差勁也要實作業務之後,重新看一遍代碼,優化代碼結構,釋放掉不必要的變量,改掉太消耗記憶體的操作。
部落客這裡優化之後,原來的代碼1280M的記憶體都不夠用,現在128M的記憶體妥妥的。程式執行下來,總共占用記憶體10M左右,還是比較合适的。如果大家也出現記憶體不足的情況,那麼除了增大學身的php記憶體之外,也要考慮優化下程式哦。
有需要交流的小夥伴可以點選這裡加本人QQ:luke
最好的貴人
就是拼命努力的自己。