如何在运行Symfony 1.4任务时使用更少的内存?

17

我正在使用Symfony 1.4和Doctrine。

到目前为止,我在Symfony中运行任务没有任何问题。 但是现在我需要导入大量数据并将它们保存在数据库中,我遇到了臭名昭著的

  

"Fatal Error: Allowed memory size of   XXXX bytes exhausted"

在此导入期间,我只创建新对象,设置一些字段并保存它们。

我非常确定这与在保存数据时创建的对象数量有关。然而,取消设置这些对象没有任何效果。

在Symfony中有什么最佳实践来限制内存使用?


1
+1好问题,这是Symfony文档中没有涵盖的内容! - richsage
避免内存泄漏的另一种方法 https://dev59.com/v3I95IYBdhLWcg3w5iY4#4066680 - j0k
8个回答

11

我遇到了这个问题,我发现有一些技巧可以有效地减少Doctrine的内存使用。

1:尽可能将Doctrine查询结果转化为数组形式。您可以按照以下方式执行:

$query = self::createQuery("q")->
  ...
  ->setHydrationMode(Doctrine::HYDRATE_ARRAY)
  ->execute();

这会强制Doctrine不创建大对象,而是将其缩小为数组。显然要记住,如果您这样做,就会失去调用方法等的能力,因此只有在用于读取字段值等情况下才有效。

2:执行后释放结果。虽然Doctrine文档中只有很小的一部分介绍了这个功能,但它确实对我正在使用的导入任务有所帮助:

$query->free();

就是这样。您也可以在创建的对象上执行此操作,例如:$myObj->free();,这将强制Doctrine删除其创建的所有循环引用。请注意,在通过PHP作用域或unset()删除对象时,从PHP 5.3开始自动释放循环引用,但在此之前您需要自行处理。

在使用变量后取消设置它们也会有所帮助,尽管请与上述free()方法一起使用,因为否则unset()不会清除循环引用。


4
尝试这个:

试一下:

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

php/symfony/doctrine 内存泄漏?

Jordan Feldstein 的回答,不是我的。


4

为了减少任务内存使用量,另一个提示是禁用查询分析器。 大量的查询往往会使任务使用越来越多的内存。

要做到这一点,请在您的database.yml配置文件中创建一个新的任务环境,并添加以下行:

task:
  doctrine:
    class: sfDoctrineDatabase
    param:
      profiler: false

然后在“task”环境中设置您的任务运行。如果您的查询在循环中,它应该有助于保持内存使用稳定。


2
抱歉回答晚了,但希望能帮到有需要的人。
另一个可能会极大节省内存的方法是确保 Symfony 的调试模式未启用。在一些长时间运行的任务中,我添加了这行代码后,即使我已经优化了像水合模式这样的东西,它也减少了约 40% 的 RAM 使用量。
sfConfig::set('sf_debug', false);

1

在使用Doctrine查询中的fetchOne()函数时要小心。这个函数调用不会在SQL语句中添加"Limit 1"。

如果你只需要从数据库获取一条记录,请确保:

$q->limit(1)->fetchOne() 

大表的内存使用量非常高。

您可以看到fetchOne()会首先从数据库中获取一个集合,然后返回第一个元素。

public function fetchOne($params = array(), $hydrationMode = null)
{
    $collection = $this->execute($params, $hydrationMode);

    if (is_scalar($collection)) {
        return $collection;
    }

    if (count($collection) === 0) {
        return false;
    }

    if ($collection instanceof Doctrine_Collection) {
        return $collection->getFirst();
    } else if (is_array($collection)) {
        return array_shift($collection);
    }

    return false;
}

1

我在symfony的PHP批处理作业中遇到了同样的问题——如果它们运行很长时间并使用大量数据,它们往往会膨胀,即使我制作了一个调用许多单独的PHP进程的包装器,也没有帮助。

因此,我用Perl的DBI重写了我的更大的批处理作业,它们是可靠和可管理的。

我不是在建议这是最好的答案,只是表示同情并提供我的经验。可能有一种方法可以使PHP表现更好。


0

在此之前,您应该启用垃圾回收 => gc_enable() - kirugan

0

同时尝试仅在查询中限制需要的(选择)字段。

例如使用以下内容:

$query = self::createQuery("q")->
  ->select('id','title','price')
  ...

改为:

$query = self::createQuery("q")->
  ->select('*')
  ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接