【问题标题】:Is this normal memory behaviour?这是正常的记忆行为吗?
【发布时间】:2026-01-25 12:15:01
【问题描述】:

我有一个处理大型 XML 文件并将其中的数据保存到数据库中的 php 脚本。在保存到数据库之前,我使用几个类来处理和存储 PHP 脚本中的数据,并逐个节点读取 XML 以保留内存。基本上,我的文件中的循环如下所示:

while ($Reader->read()) {
        $parsed++;
        if (time() >= $nexttick) {
            $current=microtime(true)-$ses_start;
            $eta=(($this->NumberOfAds-$parsed)*$current)/$parsed;
            $nexttick=time()+3;
            $mem_usage=memory_get_usage();

            echo "Parsed $parsed @ $current secs \t | ";
            echo " (mem_usage: " . $mem_usage . " \t | ";
            echo "ETA: $eta secs\n";
        }

        $node=$Reader->getNode();
        // OMMITED PART: $node is an array, I make some processing, and check if everything exists in the array that I need in the following section

        $Ad=new Ad($node); // creating an Ad object from the node

        // OMMITED PART: Making some additional SQL queries, to check the integrity of the data, before uploading it to the database


        if (!$Ad->update()) {
            //add wasn't inserted succesfully, saving a row in a second database table, to log this information
        } else {
            //add succesfully inserted, saving a row in a second database table, to log this information
        }
}

您注意到,循环的第一部分是一个小输出工具,每 3 秒输出一次文件的进度,还输出脚本的内存使用情况。我需要它,因为我遇到了内存问题,上次我尝试上传文件时,想弄清楚是什么在消耗内存。

当我运行这个脚本时,它的输出看起来像这样:

解析 15 @ 2.0869598388672 秒 | (mem_usage:1569552 | ETA:1389.2195994059 秒 解析 30 @ 5.2812438011169 秒 | (mem_usage:1903632 | ETA:1755.1333565712 秒 解析 38 @ 8.4330480098724 秒 | (mem_usage:2077744 | ETA:2210.7901124829 秒 解析 49 @ 11.377414941788 秒 | (mem_usage:2428624 | ETA:2310.5440017496 秒 解析 59 @ 14.204828023911 秒 | (mem_usage:2649136 | ETA:2393.3931421304 秒 解析 69 @ 17.032008886337 秒 | (mem_usage:2831408 | ETA:2451.3750760901 秒 解析 79 @ 20.359696865082 秒 | (mem_usage:2968656 | ETA:2556.8171214997 秒 解析 87 @ 23.053930997849 秒 | (mem_usage:3102360 | ETA:2626.8231951916 秒 解析 98 @ 26.148546934128 秒 | (mem_usage:3285096 | ETA:2642.0705279769 秒 解析 107 @ 29.092607021332 秒 | (mem_usage:3431944 | ETA:2689.8426286172 秒

现在,我可以肯定地知道,在我的MySQL 对象中,我有一个运行时缓存,它将一些基本选择查询的结果存储在一个数组中,以便以后快速访问。这是脚本中唯一的变量(据我所知),它在整个脚本中的大小都会增加,所以我尝试关闭此选项。内存使用量下降了,但只有一点点,而且在整个脚本中它仍在上升。

我的问题如下:

  1. 在长时间运行的脚本中,内存使用量的缓慢上升是 php 中的正常行为,还是我应该搜索整个代码,并尝试找出是什么占用了我的内存?

  2. 我知道通过在变量上使用unset(),我可以释放它从内存中占用的空间,但是我是否需要使用unset(),即使我在整个过程中都覆盖了同一个变量整个文件?

用一个例子稍微改写我的第二个问题:

以下两个代码块在内存使用方面是否产生相同的结果,或者如果不是,哪一个更优化?

BLOCK1

 $var = str_repeat("Hello", 4242);
 $var = str_repeat("Good bye", 4242);

BLOCK2

 $var = str_repeat("Hello", 4242);
 unset($var);
 $var = str_repeat("Good bye", 4242);

【问题讨论】:

  • Block1 和 Block2 的内存使用量相同,但 block2 会因为 $var 的取消设置和重新创建而变慢
  • slow rising of the memory usage throughout a long running script 是可能的,但循环内的 slow rising of the memory usage throughout a long running script 很少见,除非循环正在构建一个数组或类似的......看起来循环内的某些东西正在消耗内存而不是释放它
  • 嗯,这正是我所害怕的。在这种情况下,我需要逐个调试循环使用的每个函数:|
  • blackfire.io 或 xdebug 等工具可以帮助完成该过程

标签: php memory


【解决方案1】:

如果你在你的开发机器上安装了 xdebug 模块,你可以让它做一个函数跟踪——这将显示每一行的内存使用情况——https://xdebug.org/docs/execution_trace

这可能会帮助您确定空间上升的位置 - 然后您可以尝试 unset($var) 等,看看它是否有任何不同。

【讨论】: