【问题标题】:unusual memory allocation php异常的内存分配php
【发布时间】:2013-08-19 14:40:00
【问题描述】:

我正在尝试从许多 html 文件中提取数据文件。为了快速完成,我不使用 DOM 解析器,而是使用简单的strpos()。如果我从大约 200000 个文件生成,一切顺利。但是如果用更多的文件(300000)来做,它什么也不输出,并且会产生这种奇怪的效果: 看下图。 (上面是 CPU)在第一个(标记为红色)阶段,输出文件大小正在增长,一切似乎都很好。之后(标记为橙色)文件大小变为零并且内存使用量正在增长。 (一切都是两次,因为我在中场休息时重新开始计算)

我忘了说我使用 WAMP。

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

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

这里是代码。

$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

【问题讨论】:

  • 如果是内存问题,我认为它会在您的错误日志中生成一个致命错误,对吧?另外,您是否尝试过在迭代时打开/关闭 $datafile?也许您可以尝试使用 file_get_contents 将其作为套接字打开?
  • 你能显示你用来打开和关闭输出文件的代码吗?您是否尝试从命令行运行脚本?
  • @AaronSaray PHP 错误日志为空。我打开/关闭它但没有修改。如何将其作为套接字打开?
  • 我已插入 apache 错误日志。
  • @Enzino 代码已更新。我总是从浏览器打开脚本。

标签: php memory-management file-io wamp


【解决方案1】:

您应该考虑从命令行运行脚本;这样您就可以在不深入查看错误日志的情况下发现错误。
此外,如PHP manual 中所述,strpos 函数可能返回布尔值 FALSE,但也可能返回非布尔值,其计算结果为 FALSE,因此测试此函数返回值的正确方法是使用 @ 987654322@:

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

【讨论】:

    【解决方案2】:

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

    查看代码,我猜你已经达到file_get_contents 正在读取一些大文件并且 PHP 意识到它必须通过运行垃圾收集来释放一些内存才能存储它的内容。

    解决这个问题的最佳方法是连续读取文件并按块处理它,而不是把它整个放在内存中。

    【讨论】:

    • 使用“file_get_contents”加载的文件很小(~20 KB),但很多
    【解决方案3】:

    大量数据正在进入系统内部缓存。当系统缓存的数据写入磁盘时,可能会对内存和性能产生影响。

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

    (不过,这说明不是空文件,除非有windows bug。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-06
      • 2015-06-02
      • 1970-01-01
      • 2013-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      相关资源
      最近更新 更多