一、前言
這篇文章其實是上篇文章的記憶體優化部分,博主的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{
$this->arrEsIndex = $arr;
}
優化點評: 像這種陣列賦值操作盡量少做,因為把 $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
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/125408.html
標籤:PHP
