Doctrine транзакция, использующая слишком много памяти - PullRequest
4 голосов
/ 21 мая 2011

Я продолжаю получать эту ошибку при запуске одного из моих сценариев;

Неустранимая ошибка PHP: исчерпан допустимый объем памяти 1073741824 байта (попытался выделить 71 байт) в ... lib / symfony-1.4.11 / lib / plugins / sfDoctrinePlugin / lib / vendor / doctrine / Connection / Statement.php в строке 246, ...

Ниже приведена сокращенная версияскрипт, который вызывает ошибку;

public function executeImportFile(sfWebRequest $request)
{
 ini_set('memory_limit', '1024M');
 set_time_limit ( 0 );

 //more codes here...

 $files = scandir($workspace.'/'.$directory);

 foreach ($files as $file) {
   $path = $workspace.'/'.$directory.'/'.$file;

   if ($file != "." && $file != "..") {
     $this->importfile($path);
   }
 }
}


protected function importfile($path){


 $connection =
sfContext::getInstance()->getDatabaseManager()->getDatabase('doctrine')->getDoctrineConnection();
 $connection->beginTransaction();
 try {

   //more codes here...


   while ($data = $reader->read()) //reads each line of a csv file
   {
     // send the line to another private function to be processed
     // and then write to database
     $this->writewave($data);
   }


   $connection->commit();

 } catch (Exception $e) {
   $connection->rollback();
 }
}

Что скрипт делает в основном, чтобы прочитать все файлы CSV в папке (которая содержит десятки тысяч строк в каждом), обработать его и записать его вбазы данных с использованием транзакции Doctrine.

Хотя я не думаю, что мне нужно устанавливать ограничение памяти и ограничение времени в обеих функциях, сценарий завершается, поскольку Doctrine использует все выделенные 1 ГБ памяти.

Обычно он останавливается после обработки 10 файлов, а выделение большего объема памяти позволяет обрабатывать немного больше файлов и все равно приводит к сбою.

Есть что-то, что я пропускаюЧто здесь, что заставляет память не освобождаться после обработки каждого файла?

Мохд Шакир Закария http://www.mohdshakir.net

Ответы [ 3 ]

4 голосов
/ 22 мая 2011

По возможности освобождайте любые объекты, в том числе объекты запросов / соединений, особенно когда они внутри циклов.

http://docs.doctrine -project.org / projects / doctrine1 / en / latest/en/manual/improving-performance.html#free-objects

1 голос
/ 21 мая 2011

Doctrine использует заведомо много памяти при работе с большими наборами данных - таким образом импорт больших / нескольких файлов невозможен.

Даже если вы импортируете каждый файл в отдельном вызове функции, доктрина имеет внутренний кэш объектов, поэтому они не освобождаются.

Лучшим вариантом будет немного изменить задачу, чтобы она принимала имя файла в качестве параметра. Если он пропущен, обработайте только этот файл (надеясь, что он не станет слишком большим). Если имя файла не передается, оно перебирает все файлы, как сейчас, и вызывает себя через exec, так что это другой процесс, и память действительно освобождается.

0 голосов
/ 21 мая 2011

самая большая проблема, которую я вижу в вашем скрипте, заключается в том, что вы часто вызываете sfcontext. ИМХО sfcontext не является синглтоном, что означает, что вы создаете новый экземпляр каждый цикл. Не могли бы вы передать соединение в метод?

public function executeImportFile(sfWebRequest $request)
{
 ini_set('memory_limit', '1024M');
 set_time_limit ( 0 );


$connection = sfContext::getInstance()->getDatabaseManager()->getDatabase('doctrine')->getDoctrineConnection();

 //more codes here...

 $files = scandir($workspace.'/'.$directory);

 foreach ($files as $file) {
   $path = $workspace.'/'.$directory.'/'.$file;

   if ($file != "." && $file != "..") {
     $this->importfile($path, $connection);
   }
 }
}


protected function importfile($path, $connection){
 $connection->beginTransaction();
 try {

   while ($data = $reader->read()) //reads each line of a csv file
   {
     $this->writewave($data);
   }
  $connection->commit();

 } catch (Exception $e) {
   $connection->rollback();
 }
}
...