我刚刚发现了在
PHP中泄漏内存的困难方法.我在循环中运行一些代码,并且在每个循环之后内存使用量增加,直到脚本达到内存限制.我已经确定了:
>没有全局变量(我相信也没有静态变量)
>我正在运行PHP 5.4,据说它有一个新的垃圾收集器用于循环引用
>每个循环后,我的所有变量都超出范围
>我在每个周期后调用gc_collect_cycles()
这是一个示例脚本,演示了有关PhpExcel library的问题:
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_Calculation::$_workbookSets
获取对每个工作簿的PHPExcel_Calculation对象的引用.每次do_it()运行时都会增长.因为对象因此永远不会超出范围,所以无法回收它们的内存及其属性等.
替换你的未设置(…);使用PHPExcel_Calculation::unsetInstance($phpexcel);
并且内存泄漏消失,因为这会从该数组中删除关联的对象(并且仅执行该操作).
对于一般问题:循环引用不是问题,垃圾收集器处理它们就好了 – 避免全局(静态只是花哨的全局),因为它们可以很好地隐藏并且气球失控.