2012-01-29 25 views
1

对于我的一个项目,我需要导入一个非常大的文本文件(约950MB)。我为我的项目使用了Symfony2 & Doctrine 2。PHP内存调试

我的问题是,我得到这样的错误:

Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 24 bytes) 

的错误,即使我增加内存限制为1GB发生。

我尝试用了XDebug和KCacheGrind(为的PHPEdit的一部分)来分析这个问题,但我实在不明白的值:(

我'寻找一种工具或方法(快速& 。简单归因于事实,我没有太多的时间),找出为什么内存分配,而不是再次释放

编辑

要在这里明确一些事情是我的代码:

$handle = fopen($geonameBasePath . 'allCountries.txt','r'); 

     $i = 0; 
     $batchSize = 100; 

     if($handle) { 
      while (($buffer = fgets($handle,16384)) !== false) { 

       if($buffer[0] == '#') //skip comments 
        continue; 
       //split parts 
       $parts = explode("\t",$buffer); 


       if($parts[6] != 'P') 
        continue; 

       if($i%$batchSize == 0) { 
        echo 'Flush & Clear' . PHP_EOL; 
        $em->flush(); 
        $em->clear(); 
       } 

       $entity = $em->getRepository('MyApplicationBundle:City')->findOneByGeonameId($parts[0]); 
       if($entity !== null) { 
        $i++; 
        continue; 
       } 

       //create city object 
       $city = new City(); 

       $city->setGeonameId($parts[0]); 
       $city->setName($parts[1]); 
       $city->setInternationalName($parts[2]); 
       $city->setLatitude($parts[4]); 
       $city->setLongitude($parts[5]); 
       $city->setCountry($em->getRepository('MyApplicationBundle:Country')->findOneByIsoCode($parts[8])); 

       $em->persist($city); 

       unset($city); 
       unset($entity); 
       unset($parts); 
       unset($buffer); 

       echo $i . PHP_EOL; 


       $i++; 
      } 
     } 

     fclose($handle); 

事情我都试过了,但没有任何帮助:

  1. 添加第二个参数与fgets
  2. 增加memory_limit的
  3. 取消设置瓦尔
+0

当我们知道可能有临时的大内存使用情况(如下载2GB文件等)时,我们曾经为某些脚本设置内存限制为20GB。 :) – Vyktor 2012-01-29 16:03:45

+1

这只是疯了。不是每个人都有20GB的内存。认真... – 2012-01-29 16:50:28

+0

我已经看到了在taskmanager中的php进程,内存使用量不断上升。我有C++或Objective-C的这个问题,因为我忘记了_delete_或_release_,但从未使用php – Frido 2012-01-29 19:04:47

回答

5

增加内存的限制不会是不够的。当导入这样的文件时,你缓冲读数。

$f = fopen('yourfile'); 
while ($data = fread($f, '4096') != 0) { 
    // Do your stuff using the read $data 
} 
fclose($f); 

更新:

当使用ORM工作,你必须明白,没有什么是数据库中的实际插入,直到冲洗通话。意味着所有这些对象都被标记为“待插入”的ORM存储。只有在进行刷新调用时,ORM才会检查收集并开始插入。

解决方案1 ​​:经常冲洗。并且清楚。

解决方案2:不要使用ORM。去纯朴的SQL命令。它们将比对象+ ORM解决方案占用的内存少得多。

+0

我正在使用_fgets_是不是一样? – Frido 2012-01-29 20:04:27

+0

不是,当检查http://php.net时,你可以看到他们没有这样做。 'fread'只是从文件中读取字节。 'fgets'用于阅读线条,读取给定的位置。 – 2012-01-29 21:16:59

+0

对不起,当我说他们是相同的,我的意思是他们都从一个文件顺序阅读。 – Frido 2012-01-29 21:42:11

0

33554432是32MB

在php.ini中更改内存限制,例如75M乙

memory_limit = 75M 

并重新启动服务器

+0

“如果我将内存限制增加到1GB,甚至会发生此错误。” – JJJ 2012-01-29 16:34:14

+1

Theres没有说950MB的文件在将它放入PHP时仍然是950MB。对于你所知道的,实际的内存数量可能会增加一倍。 – 2012-01-29 16:40:26

+0

你在做什么,file_get_contents,加载xml ... – ZiTAL 2012-01-29 16:46:04

0

而不是简单地阅读文件,你应该逐行阅读文件。每次你阅读一行你应该处理你的数据。不要试图将所有东西都放在记忆中。你会失败。原因是,尽管你可以把TEXT文件放在ram中,但你不能同时拥有php对象/变量/ whathaveyou数据,因为php本身需要大量的内存其中。

我代替建议是 一个)读取一个新行, b)中解析在线路 c中的数据)创建新的对象数据库中的 d来存储)转到步骤a,通过未设置(婷)旧对象第一次或重新使用它的内存