如何避免PHP 5.4中的内存泄漏?

我刚刚发现了在
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);并且内存泄漏消失,因为这会从该数组中删除关联的对象(并且仅执行该操作).

对于一般问题:循环引用不是问题,垃圾收集器处理它们就好了 – 避免全局(静态只是花哨的全局),因为它们可以很好地隐藏并且气球失控.

点赞