Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use less memory while running a task in Symfony 1.4?

I'm using Symfony 1.4 and Doctrine.

So far I had no problem running tasks with Symfony. But now that I have to import a pretty big amount of data and save them in the database, I get the infamous

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

During this import I'm only creating new objects, setting a few fields and saving them.

I'm pretty sure it has something to do with the number of objects I'm creating when saving data. Unsetting those objects doesn't do anything though.

Are there any best practices to limit memory usage in Symfony?

like image 458
Guillaume Flandre Avatar asked Mar 17 '10 15:03

Guillaume Flandre


4 Answers

I've come across this, and there's a couple of techniques I found really helped with Doctrine's extensive memory usage.

1: Where possible, hydrate your Doctrine query results down to an array. You can do this as follows eg:

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

This forces Doctrine to NOT create large objects, but instead reduces it to an array. Obviously bear in mind that if you do this, you lose the ability to call methods etc, so this is only good if you're using it for reading field values etc.

2: Free your results after execution. This is documented in a tiny area of the Doctrine docs, but it's really helped out the import task I was using:

$query->free();

That's it. You can also do this on objects that you've created, eg $myObj->free(); and this forces Doctrine to remove all the circular references that it creates. Note that circular references are automatically freed from PHP 5.3 onwards on deletion of an object via the PHP scope or unset(), but before that you'll need to do it yourself.

Unsetting variables after you've used them also helps, although do this in conjunction with the free() method above as mentioned, as unset() won't clear the circular refs otherwise.

like image 83
richsage Avatar answered Nov 05 '22 18:11

richsage


Try this :

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

as mentioned on

php/symfony/doctrine memory leak?

Answer from Jordan Feldstein not mine.

like image 32
jose Avatar answered Nov 05 '22 18:11

jose


Another hint for reducing the amount of memory used inside a task is to disable the query profiler. A big number of queries tends to make the task using more and more memory.

To do so create a new task environment in your database.yml config file by adding the following lines:

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

Then setup your task to run in "task" environment. It should help to keep memory usage stable if your queries are in a loop.

like image 4
Remiz Avatar answered Nov 05 '22 18:11

Remiz


Sorry I know this is a late answer, but could help someone.

Another potentially huge memory saver is to make sure Symfony's debug mode is not enabled for that task. In a couple of long-running tasks I added this line and it cut down the RAM usage about 40% even after I had optimized things like hydration mode.

sfConfig::set('sf_debug', false);
like image 2
ybull Avatar answered Nov 05 '22 19:11

ybull