我剛剛發現了可能會在PHP中泄漏內存的難題。我在循環中運行一些代碼,在每個循環之後,內存使用量會增加,直到腳本達到內存限制。我已經確信:如何避免PHP 5.4中的內存泄漏?
- 沒有全局變量(我相信沒有任何靜態)
- 我運行PHP 5.4據稱具有循環引用
- 我所有的變量,這個花哨的新垃圾收集器走出去的範圍內的每個週期
- 我每個週期
這是在考慮到演示問題的示例腳本以後打電話gc_collect_cycles()
後:
require_once(__DIR__ . '/libraries/PHPExcel/PHPExcel.php');
ini_set('memory_limit', '200M');
@mkdir(__DIR__ . '/output');
gc_enable();
for ($n = 0 ; $n < 10 ; $n++)
{
do_it($n);
gc_collect_cycles();
}
function do_it($n)
{
echo 'Round '.$n.'...';
$text = str_repeat('x', 50000);
$phpexcel = new PHPExcel();
$worksheet = $phpexcel->getActiveSheet();
for ($r = 1 ; $r < 50 ; $r++)
for ($c = ord('A') ; $c <= ord('S') ; $c++)
$worksheet->setCellValueExplicit(chr($c) . $r, $text, PHPExcel_Cell_DataType::TYPE_STRING);
// $phpexcel->disconnectWorksheets();
unset($phpexcel, $worksheet);
echo 'done, now using ' . round((memory_get_usage())/1024/1024).' MB' . "\n";
}
輸出:
Round 0...done, now using 41 MB
Round 1...done, now using 80 MB
Round 2...done, now using 123 MB
Round 3...done, now using 157 MB
Round 4...
Fatal error: Allowed memory size of 209715200 bytes exhausted (tried to allocate 36 bytes)
現在對於這個特定的問題the solution is每個週期,這取消設置一些對象成員之後調用$phpexcel->disconnectWorksheets();
。
真正的問題是:作爲一名PHP程序員,我該怎麼做才能避免這種內存泄漏?在我可以取消設置對象之前,是否真的必須遞歸遍歷每個對象以取消其成員的設置?
我認爲這個問題可以更準確地概括爲「什麼是PHPExcel阻止循環引用垃圾回收器完成其工作?」。他們清楚地知道這是一個問題,因爲他們首先創建了'PHPExcel :: disconnectWorksheets()'函數(儘管這可能早於PHP 5.3中的新垃圾回收器)。通常我會說這會在他們的論壇/郵件列表中得到更好的回答,但他們似乎也沒有。 – Phylogenesis
@Phylogenesis這是正確的,問題是或多或少「我能做些什麼來攪亂垃圾收集器?」所以我可以避免它。 – AndreKR
我用'phpexcel'標記了這個問題,希望@MarkBaker會來解釋他的想法。 :) – AndreKR