php / symfony / doctrine内存泄漏?

时间:2010-01-19 22:41:27

标签: php memory-leaks symfony1 doctrine

我在使用symfony 1.4和doctrine 1.2将对象批量插入数据库时​​遇到问题。

我的模型有一种称为“扇区”的对象,每个对象都有几个“Cupo”类型的对象(通常范围从50到200000)。这些物体非常小;只是一个短标识符字符串和一个或两个整数。每当用户创建一组扇区时,我需要自动将所有这些“Cupo”实例添加到数据库中。如果出现任何问题,我正在使用一个学说交易来回滚所有内容。问题是我只能在php耗尽内存之前创建大约2000个实例。它目前有128MB的限制,应该足以处理使用少于100个字节的对象。我已经尝试将内存限制增加到512MB,但是php仍然崩溃,但这并没有解决问题。我正确地进行批量插入还是有更好的方法?

这是错误:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 71 bytes) in /Users/yo/Sites/grifoo/lib/vendor/symfony/lib/log/sfVarLogger.class.php on line 170

这是代码:

public function save($conn=null){

    $conn=$conn?$conn:Doctrine_Manager::connection();

    $conn->beginTransaction();


    try {
        $evento=$this->object;


        foreach($evento->getSectores() as $s){

            for($j=0;$j<$s->getCapacity();$j++){

                $cupo=new Cupo();
                $cupo->setActivo($s->getActivo());
                $cupo->setEventoId($s->getEventoId());
                $cupo->setNombre($j);
                $cupo->setSector($s);

                $cupo->save();

            }
        }

        $conn->commit();
        return;
    }
    catch (Exception $e) {
        $conn->rollback();
        throw $e;
    }

再次,此代码适用于少于1000个对象,但任何大于1500的代码都会失败。谢谢你的帮助。

9 个答案:

答案 0 :(得分:33)

尝试做

$cupo->save();
$cupo->free();
$cupo = null;

(但代替我的代码)而且我仍然会得到内存溢出。还有其他想法吗?

<强>更新

我在databases.yml中创建了一个新环境,如下所示:

all:
  doctrine:
    class: sfDoctrineDatabase
    param:
      dsn: 'mysql:host=localhost;dbname=.......'
      username: .....
      password: .....
      profiler: false

profiler:false 条目会禁用doctrine的查询日志记录,通常会保留您进行的每个查询的副本。它并没有阻止内存泄漏,但是通过我的数据导入,我能够获得大约两倍的内存泄漏。

更新2

我添加了

Doctrine_Manager::connection()->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true ); 

在运行我的查询之前,并更改了

$cupo = null;

unset($cupo);

现在,我的剧本一直快乐地流着。我很确定它会在没有耗尽RAM的情况下完成。

更新3

烨。这是获胜的组合。

答案 1 :(得分:3)

我刚刚使用symfony 1.4执行了“daemonized”脚本,并设置以下内容停止了内存占用:

sfConfig::set('sf_debug', false);

答案 2 :(得分:3)

对于symfony任务,我也遇到了这个问题,并完成了以下事情。它对我有用。

  • 禁用调试模式。在db connection initialize

    之前添加以下内容
    sfConfig::set('sf_debug', false);
    
  • 为数据库连接设置自动查询对象的免费属性

    $connection->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true );
    
  • 使用后释放所有对象

    $object_name->free()
    
  • 使用unset($array_name)

  • 后取消设置所有数组
  • 检查在任务中使用的所有学说查询。使用后释放所有查询。 $q->free() (对于任何使用查询的时间,这都是一个很好的做法。)

这就是全部。希望它可以帮助某人。

答案 3 :(得分:2)

学说泄漏,你无能为力。确保在适用时使用$ q-&gt; free()以最小化效果。 Doctrine不适用于维护脚本。解决此问题的唯一方法是将脚本分解为将执行部分任务的部分。一种方法是在脚本中添加一个start参数,在处理完一定数量的对象后,脚本会以更高的起始值重定向到自身。这对我来说很有效,尽管它使编写维护脚本变得更加麻烦。

答案 4 :(得分:1)

每次保存后尝试unset($cupo);。这应该是有帮助的。另一件事是拆分脚本并进行一些批处理。

答案 5 :(得分:1)

尝试打破循环引用,这通常会导致内存泄漏

$cupo->save();

$cupo->free(); //this call

作为Doctrine手册中的described

答案 6 :(得分:1)

对我来说,我刚刚初始化了这样的任务:

// initialize the database connection
$databaseManager = new sfDatabaseManager($this->configuration);
$connection = $databaseManager->getDatabase($options['connection'])->getConnection();
$config = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', true);
sfContext::createInstance($config);

(WITH PROD CONFIG)
并在doctrine对象

上的save()之后使用free()

记忆稳定在25Mo

memory_get_usage=26.884071350098Mo

使用php 5.3 on debian squeeze

答案 7 :(得分:0)

定期关闭并重新打开连接 - 不确定原因,但似乎PDO保留了引用。

答案 8 :(得分:0)

对我有用的是调用free这样的方法:

$cupo->save();
$cupo->free(true); // free also the related components
unset($cupo);