2015-09-14 52 views
1

該函數傳遞約70k個對象進行處理。加載數組並沒有問題,並且在它失敗之前它會經歷大約一半的迭代。內存限於ini_set('memory_limit','465M');(雲服務)。它總是在$googleFunction/app/vendor/googleads/googleads-php-lib/src/Google/Api/Ads/Common/Lib/AdsSoapClient.php中失敗。如何在PHP中優化此功能的內存使用情況?

我已經嘗試傳遞數組作爲基準,切換從array_chunk到使用array_slice在一個時間,通過引用傳遞$chunk$googleFunction,在端部取消設置$chunk,並調用在每次迭代之後gc_collect_cycles()

它又如何失敗?必須有某處存在內存泄漏,但除$chunk$result之外沒有大的分配,並且在每次迭代過程中調用的每個函數都會超出範圍,因此可能分配的任何內容都應該被垃圾收集。我覺得它可能與函數引用有關。經過約四分之一的迭代後,它使用240M。它每次迭代增長約10M。

function googleJob($job = null, &$list, $googleFunction, $before = null) { 
    // initialize $total, $gaw, $processed 
    for ($chunkIndex = 0; $chunkIndex < count($list); $chunkIndex += 2000) { 
     echo '3:'.memory_get_usage().' '; 
     $chunk = array_slice($list, $chunkIndex, 2000); # limit of 2000/request 
     echo '4:'.memory_get_usage().' '; 
     if ($before) { 
     foreach ($chunk as $item) { 
      $before($item); # function reference 
     } 
     } 
     echo '5:'.memory_get_usage().' '; 

     $i = 0; // try harder to make Google work 
     $result = null; 
     do { 
     try { 
      $result = $gaw->$googleFunction($chunk); 
      echo '6:'.memory_get_usage().' '; 
     } catch (\SoapFault $e) { # try to remove the bad items and try again 
      // no errors generated 
     } 
     } while ($result == null && $chunk); // Retry the request if not empty 

     array_walk($chunk, function($item) { $item->save(); }); 
     echo '7:'.memory_get_usage().' '; 
     $processed += count($chunk); 
     if ($job) { 
     $job->progress = round($processed/$total * 100); 
     $job->save() or Yii::error($job->getErrors()); 
     } 
     echo '8:'.memory_get_usage().' ';  
     unset($chunk); 
     unset($result); 
     echo '9:'.memory_get_usage().'... '; 
     gc_collect_cycles(); 
     echo memory_get_usage().PHP_EOL; 
    } 
    } 

記憶 '剖析' 輸出:

3:110267832 4:110372112 5:111920328 6:123908368 7:129432080 8:129432080 9:121662520... 121662520 
3:121662520 4:121766800 5:123281704 6:138001000 7:143493888 8:143493888 9:135745264... 135745264 
+0

可能會或可能不會與此有關,但[本博客](http://blog.ircmaxell.com/2014/ 12/what-about-garbage.html)詳細描述了垃圾收集的功能。我從來沒有想過告訴PHP如何管理內存。它的設計並非如此。 – Machavity

+0

您可能想考慮使用隊列來處理這些作業 – FuzzyTree

+0

將'$ list'作爲參考傳遞沒有意義,因爲您從不修改該數組。 – Barmar

回答

1

在我看來,你是濫用SOAP服務。如果您告訴我們您的代碼在$ googleFunction失敗,我可以爲您提供$ 100或200個對象的$ chunk。第二件事是$ item-> save()函數。如果您有權訪問課程,您應該檢查是否有HAS-IS課程。唯一的地方PHP泄漏內存是這樣的結構:

class Foo { 
    function __construct() 
    { 
     $this->bar = new Bar($this); 
    } 
} 

class Bar { 
    function __construct($foo = null) 
    { 
     $this->foo = $foo; 
    } 
} 



for($i = 0; $i < 10; $i++){ 

    $foo = new Foo(); 
    unset($foo); 
    echo number_format(memory_get_usage()) . "<br>"; 

} 

所以如果你有對象,我懷疑活動記錄的對象,在保存()函數創建不要忘了取消或修改它們。 簡單的方法是添加毀滅這樣的:

function __destruct() 
    { 
     unset($this->bar); 
    } 

這應該有助於

+0

[Google推薦2000](https://developers.google.com/adwords/api/docs/appendix/limits#general),並支持多達5000個。但我會一次嘗試100個,並測試泄漏情況循環參考。即使有200個小塊,它仍然會泄漏。 – Chloe

+0

有趣的是''save()'確實會泄漏內存! 'foreach($ agk as $ v){ $ v-> save(); echo memory_get_usage()。PHP_EOL; }' – Chloe

+0

好吧,我已經爲Yii提交了一個錯誤報告。 https://github.com/yiisoft/yii2/issues/9679 – Chloe

相關問題