2012-01-29 54 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,通過未設置(婷)舊對象第一次或重新使用它的內存