The abyss of memory

I am using Behat to test a Symfony2 application. Despite the fact that each function test succeeds when it is executed in isolation, an attempt to run the entire test package at a time causes PHP to run out of memory - even if memory_limit is set to 2 GB or higher.

Repeating the current memory usage at the end of each function, I see that the memory usage is increased by 20-50 MB for each function that is executed.

So my question is, "is there anything I can do to free memory after running each function?" It seems that each function loads a different Symfony application, so the ideal solution would be to destroy every Symfony application (provided that this happens) after each function is launched using the @AfterFeature hook.

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

Updated to add: Typical use case:

  • use the Doctrine to translate a system / entities into a known state;
  • simulate a user clicking on various links, filling out form fields, etc.
  • use Doctrine to verify that entities are an expected state
+7
php symfony behat
source share
1 answer

As a rule, PHP software is not written in such a way as to be able to release memory. Instead, the software relies on the fact that it will most likely only work for a second or two until completion, thereby clearing the memory.

When you run such tests, you are likely to get a memory leak in the main application. Add additional memory checks around functions called by the code, and then around functions that call these functions, etc., until you find the culprit.

In my experience, the problem, as a rule, is to reuse the object variable in a loop:

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

Usually, when "f" is completed, all memory is cleared. But PHP is stupid, so it computes this by looking at local variables or something like that, because only the last $ x will be cleared. Those that were created before in this loop will only flow until the script exits.

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

 $x = new C($item); $x->doStuff(); unset($x); 
+2
source share

All Articles