Doctrine事务使用太多内存问题

时间:2011-05-21 05:52:54

标签: php orm symfony1 doctrine

运行我的一个脚本时,我一直收到此错误;

  

PHP致命错误:允许的内存大小   1073741824字节耗尽(尝试过   分配71个字节)...   LIB / symfony的-1.4.11 / LIB /插件/ sfDoctrinePlugin / LIB /供应商/教义/学说/连接/ 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();
 }
}

脚本的作用基本上是读取a中的所有csv文件 文件夹(每个包含数万行),处理它, 并使用Doctrine的事务将其写入数据库。

虽然我认为我不需要设置内存限制和时间限制 在这两个函数中,脚本退出,因为Doctrine用完所有的 分配1GB内存。

处理10个文件后,通常会停止,并分配更多文件 内存将允许它处理更多的文件,并将仍然 崩溃。

我在这里缺少什么导致记忆没有的东西 处理完每个文件后可以自由使用吗?

Mohd Shakir Zakaria http://www.mohdshakir.net

3 个答案:

答案 0 :(得分:4)

尽可能释放任何对象,包括查询/连接对象,尤其是当它们位于循环内时。

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

答案 1 :(得分:1)

在使用大型数据集时,Doctrine使用了大量的内存 - 以这种方式导入大型/多个文件是不可能的。

即使您在单独的函数调用中导入每个文件,doctrine也有一个内部对象缓存,因此它们不会被释放。

您最好的选择是稍微修改一下任务,因此它接受一个文件名作为参数。如果它被传递,只处理该文件(希望它不会太大)。如果没有传递文件名,它会像现在一样循环遍历所有文件,并通过exec调用自身,所以它是一个不同的进程,内存真的被释放了。

答案 2 :(得分:0)

我在你的脚本中看到的最大的问题是你经常调用sfcontext。 IMHO 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();
 }
}