PHP脚本内存泄漏问题

5

我正在使用命令行运行以下PHP代码。问题是,它的内存消耗远远超过了应有的水平。我无论如何也找不出内存消耗的原因。

for ($i=0;$i<100;$i++)  
        {
            $classObject = $classObjects[$i];                       

            echo $i . "   :   " . memory_get_usage(true) . "\n";
            $classDOM = $scraper->scrapeClassInfo($classObject,$termMap,$subjectMap);           
            unset($classDOM);           
        }

根据我的观察,循环迭代后,脚本所消耗的内存应该保持大致不变。任何由$scraper->scrapeClassInfo()所消耗的内存,应在其成员超出作用域时得到释放。

这是我得到的输出文件。为了简洁起见,我展示每10行输出:

0   :   5767168
10   :   12058624
20   :   18350080
30   :   24903680
40   :   30932992
50   :   37748736
60   :   43778048
70   :   49807360
80   :   55836672
90   :   62914560
97   :   66846720

Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 44 bytes) in /home/content/60/8349160/html/drexel/simple_html_dom.php on line 1255

最后,就我所看到的而言,$scraper->scrapeClassInfo() 所做的事情并不是罪魁祸首,但以防万一,这里是代码:

function scrapeClassInfo($class,$termMap,$subjectMap)
        {
            $ckfile = tempnam ("/tmp", "CURLCOOKIE");
            $ckfile2 = tempnam ("/tmp", "CURLCOOKIE2");
            $ckfile3 = tempnam ("/tmp", "CURLCOOKIE3");         

            $termpage = $termMap[$class['termcode']];
            $subjectpage = $subjectMap[$class['subjectcode']];
            $classpage = $class['classlink'];

            //hit the main page and get cookie
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_COOKIEJAR, $ckfile);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_URL, $this->mainURL);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_exec($ch);
            curl_close($ch);

            //hit the term page and get cookie
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile);
            curl_setopt($ch, CURLOPT_COOKIEJAR, $ckfile2);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_URL, $termpage);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_exec($ch);
            curl_close($ch);

            //hit the subject page and get cookie
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_COOKIEJAR, $ckfile3);
            curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile2);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_URL, $subjectpage);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_exec($ch);
            curl_close($ch);

            //hit the class page and scrape
            $ch = curl_init();              
            curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile3);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_URL, $classpage);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            $result = curl_exec($ch);
            curl_close($ch);

            return str_get_html($result);
        }

最后一行调用的方法str_get_html()Simple HTML DOM解析器的成员。

如果有必要,这是我调用脚本的方式:

/usr/local/php5/bin/php index.php 2>&1 1>output

2个回答

3

好的,我明白了。显然,在 PHP 5.3 版本之前的所有版本中都存在一个错误。将 CURLOPT_RETURNTRANSFER 设置为 true 会导致大量内存泄漏。

我再次运行了脚本,这次使用了 php 5.3 二进制文件:

/web/cgi-bin/php5_3 index.php 2>&1 1>output

输出文件内容如下:

0   :   6291456
10   :   9437184
20   :   10747904
30   :   11534336
40   :   11534336
50   :   11534336
60   :   11534336
70   :   11534336
80   :   11534336
90   :   11534336
99   :   11534336
152.74998211861 sec

现在我们来谈谈这个!完美的恒定内存占用。

当我写下“将CURLOPT_RETURNTRANSFER设置为true”时,我的意思是“将CURLOPT_RETURNTRANSFER设置为true会导致大量的内存泄漏”。已编辑。 - Ayush
哦!所以问题肯定不是 CURLOPT_SSL_VERIFYPEER 吗?(参见 http://stackoverflow.com/questions/9217238/php-curl-memory-leak-when-using-curlopt-ssl-verifypeer-true) - Adam Monsen
@AdamMonsen:无法确定是哪个CURL选项导致了问题。切换到5.3二进制文件解决了这个问题。 - Ayush
好的,有趣。我很容易在RHEL 6上重现https://bugs.php.net/bug.php?id=61030,但在任何Ubuntu上都无法重现。两者都有PHP 5.3。 - Adam Monsen

1
我在你的代码中找到了以下内容。
  1. 删除 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true),因为你没有将其保存下来。
  2. 不要关闭 curl 句柄。重复使用它。

作为当前的解决方法,您可以使用更高的 memroy_limit 运行 PHP 脚本。

 $ php -d memory_limit=1G /path/to/script

1G 表示 1 千兆字节。


谢谢。肯定是朝着正确的方向。我确实尝试过删除 CUROPT_RETURNTRANSFER,但在我进行的最后一个curl请求中,我需要保留它,所以我仍然遇到了内存问题。无论如何,请参见下面的答案。 - Ayush

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接