不寻常的内存分配php

时间:2013-08-19 14:40:01

标签: php memory-management file-io wamp

我正在尝试从许多html文件中提取数据文件。为了快速完成,我不使用DOM解析器,而是使用简单的strpos()。如果我从大约200000个文件生成,一切顺利。但如果用更多的文件(300000)做它没有输出任何东西,并做这个奇怪的效果: 请看底部图。 (上面是CPU)在第一个(标记为RED)阶段,输出文件大小正在增长,一切似乎都可以。之后,(标记为ORANGE)文件大小变为零,内存使用量也在增长。 (一切都是两次,因为我在半场重新开始计算)

我忘了说我使用WAMP。

我已经厌倦了未设置的变量,将循环放入函数,使用implode而不是连接字符串,使用fopen代替filegetcontents和垃圾收集......

第二阶段是什么?我忘记了吗?是否存在一些我不知道的限制(max_execution_time,memory_limit - 已被忽略)?为什么这个小程序会占用这么多内存?

processing

这是代码。

$datafile = fopen("meccsek2b.jsb", 'w');
for($i=0;$i<100000;$i++){
    $a = explode('|',$data[$i]);
    $file = "data2/$mid.html";
    if(file_exists($file)){
        $c = file_get_contents($file);
        $o = 0;
        $a_id = array();
        $a_h = array();
        $a_d = array();
        $a_v = array();
        while($o = strpos($c,'<a href="/test/',$o)){
            $o = $o+15;
            $a_id[] = substr($c,$o,strpos($c,'/',$o)-$o);
            $o = strpos($c,'val_h="',$o)+7;
            $a_h[] = substr($c,$o,strpos($c,'"',$o)-$o); 
            $o = strpos($c,'val_d="',$o)+7;
            $a_d[] = substr($c,$o, strpos($c,'"',$o)-$o);
            $o = strpos($c,'val_v="',$o)+7;
            $a_v[] = substr($c,$o,strpos($c,'"',$o)-$o);        
        }
        fwrite($datafile,  
            $mid.'|'.
            implode(';',$a_id).'|'.
            implode(';',$a_h).'|'.
            implode(';',$a_d).'|'.
            implode(';',$a_v).
            PHP_EOL);       
    }
}
fclose($datafile);

Apache error log. (expires in 30 days)

我想我发现了问题:

由于strpos()返回0,因此存在无限循环。 分配的内存大小一直在增长,直到出现异常:

PHP Fatal error:  Out of memory 

Ensino的说明对于使用命令行非常有用,最终导致我this question

3 个答案:

答案 0 :(得分:0)

CPU峰值很可能意味着PHP正在进行garbage collection。如果您希望以更大的内存使用量获得一些性能,可以disable garbage collection by gc_disable()

看看代码,我猜,你已经达到file_get_contents读取一些大文件的地步,PHP意识到它必须通过运行垃圾收集来释放一些内存以便能够存储它的内容

如何处理这个问题的最佳方法是连续读取文件并按块处理它,而不是将其整个存储在内存中。

答案 1 :(得分:0)

大量数据进入系统内部缓存。将系统缓存的数据写入磁盘时,可能会影响内存和性能。

有一个系统函数FlushFileBuffers来enfoce写: 请查看http://msdn.microsoft.com/en-us/library/windows/desktop/aa364451%28v=vs.85%29.aspxhttp://winbinder.org/来调用该函数。

(虽然这不是空文件,除非有windows bug。)

答案 2 :(得分:0)

您应该考虑从命令行运行脚本;通过这种方式,您可以在不深入查看错误日志的情况下捕获错误 此外,如PHP manual中所述,strpos函数可能返回布尔值FALSE,但也可能返回一个非布尔值,其值为FALSE,因此测试此函数返回值的正确方法是使用the !== operator

while (($o = strpos($c,'<a href="/test/',$o)) !== FALSE){
...
}