【问题标题】:How to free memory after array in PHP? unset and = null seems to not working如何在 PHP 中的数组后释放内存? unset and = null 似乎不起作用
【发布时间】:2013-08-09 22:48:10
【问题描述】:

我有一个 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 的输出非常相似。但是在这两行之间切换 cmets

    $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 arrays performance memory


    【解决方案1】:

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

    而且 php 数组使用大量内存,因为 php 数组中的数组被实现为“hashmaps”或“hashtable”,如果您不需要字符串作为键,您可以使用 splFixedArray(真正的 C 或 C++ 数组)

    splFixedArray(您至少需要 php 5.3 才能使用它)已知使用 php 数组所需的总数的 40%。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        从 PHP > 5.3 开始,有一些可用的 Garbage Collection 机制,所以理论上你可以考虑类似文档中的示例

        //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
        

        但不幸的是,在您的情况下,您必须记住(根据Can I trigger PHP garbage collection to happen automatically if I have circular references?)垃圾收集器“不会运行,例如,当内存限制即将达到时。因此,您的脚本可以在达到内存限制时仍然会中止,只是因为 PHP 太笨了,无法在这种情况下收集循环!”。

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

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

        【讨论】:

        • 在脚本中间启用收集器将错过现有的垃圾循环,因为在未启用 GC 时不会跟踪可能的根。
        【解决方案4】:

        您可以使用unset删除变量,以便对它们进行垃圾回收。

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

        总体而言,只需跟踪您保留引用的内容即可。也许您不需要跟踪所有内容。 while-loop 可以让您提高内存效率,只需为每一行保留您需要的内容。

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

        【讨论】:

          猜你喜欢
          • 2010-10-09
          • 1970-01-01
          • 2019-11-27
          • 1970-01-01
          • 2019-02-18
          • 1970-01-01
          • 2012-07-27
          • 2014-12-20
          • 1970-01-01
          相关资源
          最近更新 更多