Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Behat eating memory

Tags:

php

symfony

behat

I'm using Behat for testing a Symfony2 application. Whilst each Feature test runs happily when run in isolation, trying to run the whole test suite in one go leads to PHP running out of memory - even when the memory_limit is set to 2GB and higher.

By echoing the current memory usage at the end of each Feature, I can see that memory usage increases by between 20 and 50MB for each feature that runs.

So, my question is, "is there anything I can do to free up memory after each Feature has run?" It appears that each Feature is booting up another Symfony application, so, my ideal solution would be to destroy each Symfony application (assuming that is what is happening) after each Feature has run using an @AfterFeature hook.

Updated to add: We're using Symfony 2.3.7 and Behat 2.5.0.

Updated to add: A typical use case is;

  • use Doctrine to put the system / entities into a known state;
  • simulate a user clicking on various links, filling in form fields etc;
  • use Doctrine to check that the entities are the expected state
like image 511
Andrew Battye Avatar asked Nov 20 '13 21:11

Andrew Battye


1 Answers

Typically, PHP software is not written in such a way to be able to release memory. Instead, the software relies on the fact that it will likely only run for a second or two before terminating, thus clearing the memory.

When you run tests like this, you are likely hitting memory leaks in the main application. Add additional memory checks around the functions being called by the code, and then around the functions those functions call, etc., until you find the culprit.

In my experience, the problem will typically be the reuse of an object variable in a loop:

function f() {
    foreach ($list as $item) {
        $x = new C($item);
        $x->doStuff();
    }
}

Normally when "f" exits, all the memory is cleaned up. But PHP is stupid, so it figures this out by looking at the local variables or something, because only the last $x is going to get cleaned up. The ones created before it in that loop will just leak until the script exits.

If this is - in fact - the problem, you can fix it by using unset on the variable before using it again.

$x = new C($item);
$x->doStuff();
unset($x);
like image 182
rich remer Avatar answered Nov 20 '22 14:11

rich remer