如何在PHP中释放数组后的内存?unset和=null似乎不起作用


How to free memory after array in PHP? unset and = null seems to not working

我得到了一个16 MB大小的CSV文件,并尝试解析它,做了一些事情,但脚本在一段时间后耗尽了内存。我意识到这段代码产生了大约200 MB的已用空间,而unset不起作用。

    $countRows = 1;
    var_dump("3. ".memory_get_usage()." beginDiff: ".(memory_get_usage() - $this->startingMemory));
    while(($row = fgetcsv($fp, 300000, ';', '"')) !== FALSE)
    {
        if ($row == '')
            continue;
        if($firstRow == true)
        {
            foreach($row as $k => $v)
            {
                $this->columnMapping[$k] = trim(mb_strtolower($v));
            }
            $firstRow = false;
            continue;
        }else
        {
            foreach($row as $k => $v)
            {
                $row[$this->columnMapping[$k]] = $v;
                unset($row[$k]);
            }
        }
    ...
        //$this->theirCategoriesToProducts[$row['kategorie']][]['kodproduktu'] = $row['kodproduktu'];
        $this->theirCategoriesToProducts[$row['kategorie']][] = $row;
    }
    var_dump("3,5.  ".memory_get_usage()." beginDiff: ".(memory_get_usage() - $this->startingMemory));
    ...
    var_dump("7. - before unset total: ".memory_get_usage()." beginDiff: ".(memory_get_usage() - $this->startingMemory));
    unset($this->theirCategoriesToProducts);
    var_dump("8. - after unset total: ".memory_get_usage()." beginDiff: ".(memory_get_usage() - $this->startingMemory));die;

生成此输出:

    string '3. 72417440 beginDiff: 34730040' (length=31)
    string '3,5.  292748528 beginDiff: 255061136' (length=36)
    string '7. - before unset total: 299039360 beginDiff: 261351984' (length=55)
    string '8. - after unset total: 297364432 beginDiff: 259677056' (length=54)

通过设置变量等于null,输出非常相似。但是在这两行之间切换注释

    $this->theirCategoriesToProducts[$row['kategorie']][]['kodproduktu'] = $row['kodproduktu'];
    //$this->theirCategoriesToProducts[$row['kategorie']][] = $row;

将输出:

    string '3. 72417784 beginDiff: 34730040' (length=31)
    string '3,5.  81081984 beginDiff: 43394248' (length=34)
    string '7. - before unset total: 87256544 beginDiff: 49568824' (length=53)
    string '8. - after unset total: 85581520 beginDiff: 47893800' (length=52)

因此,它大约有200 MB的"丢失"内存(几乎是专用内存的一半)。

递归函数取消设置数组的所有部分占用了更多的内存,因此也崩溃了。

在脚本中从未使用过该数组与&因此不应该引用其他变量。

文件在3.5转储后立即关闭。

还有其他想法吗,如何取消设置该数组?

从PHP>5.3开始,有一些垃圾回收机制可用,所以理论上你可以考虑像文档中的例子

//Memory cleanup for long-running scripts.
gc_enable(); // Enable Garbage Collector
var_dump(gc_enabled()); // true
var_dump(gc_collect_cycles()); // # of elements cleaned up
gc_disable(); // Disable Garbage Collector

但不幸的是,在您的情况下,您必须记住(根据如果我有循环引用,我可以自动触发PHP垃圾收集吗?)垃圾收集器"不会运行,例如,当内存限制即将达到时。因此,当达到内存限制时,您的脚本仍然可以中止,只是因为PHP太笨了,无法收集这种情况下的循环!"。

最后,您可以尝试使用GC,但它可能无法解决您的问题。

那么,还有什么可以尝试的呢?尝试将导入的主数据数组拆分为更小的块,然后依次导入。将循环中的块总是提取到同一个变量中,然后循环通过它来处理记录。

您可以使用unset删除变量,从而对其进行垃圾收集。

$foo = "bar";
unset($foo);
var_dump($foo); // null

总的来说,只需记录下你所引用的内容。也许你不需要记录所有内容。while-循环使您能够节省内存,只需为每一行保留所需内容。

有些脚本实际上只需要大量内存就可以运行,增加内存限制并不太疯狂,但只有在实际需要时才这样做。

PHP函数fgetcsv不好,因为服务器需要将完整的文件存储在内存中,更好地读取一行并存储

php数组使用大量内存,因为php数组中的数组被实现为"hashmap"或"hashtable",如果不需要字符串作为密钥,则可以使用splFixedArray(真正的C或C++数组)

众所周知,splFixedArray(您至少需要php5.3才能使用它)使用php数组所需的总成本的40%。

在这种情况下,在跳过的行中发现了问题。其中一个使用函数是隐藏函数,它将数组的每个部分分配给缓存全局变量。删除此缓存变量解决了问题。