0

I have a script that sometimes break because I get an error like:

PHP Fatal error: Allowed memory size of X bytes exhausted (tried to allocate Y bytes) in ...

The memory limit is NOT too low and was put at 128M. (This should be more than enough.)

The problem is that as the script goes, it takes more and more memory. Basically, it's a for loop. I've checked every variable but there is no place where the script fills 'something' (for example, an array) that would grow and explain why the script takes more memory.

I confirmed the memory problem using: memory_get_usage(). I've printed out the memory footprint after each iteration and the number is always higher.

Using Xdebug does show not any sign that can help me at this point.

Is there any way I could drilldown and know what is taking more memory everytime I loop ? What would you suggest to debug that situation ?

Maxime
  • 7,283
  • 4
  • 48
  • 49
  • 1
    Unfortunately there is no easy way of debugging memory leaks in php. Try putting the contents of the loop in a separate method or function. So your loop body is nothing but that function call. IIRC PHP's garbage collector gets called at the end of functions or methods. Since all you have is a loop, the GC is never invoked. – Mike B Mar 16 '12 at 00:31
  • Mike, I've tried your suggestion and found that calling a function vs not calling it had an impact on memory. So I know the "problem" is in that function. That said, even if I've put the code in a function and do an `unset(...)` on every variable, the memory still goes higher after every call to the function until it kills the script. GC seems to have no impact on that. – Maxime Mar 16 '12 at 15:27
  • Doh, was hoping for an easy solution. Checkout my similar question.. some of the answers might help http://stackoverflow.com/questions/849549/finding-cause-of-memory-leaks-in-large-php-stacks – Mike B Mar 16 '12 at 15:29

1 Answers1

0

The short answer is: it's not possible to drilldown.

That said, the way I found what the problem was is that I splitted the code inside the loop in subfunctions. Then, I commented them all to only check what was the footprint of looping without doing anything. Then, I've uncommented function by function until I found the problematic one.

Once I've got the problematic function, I did the same process again: comment everything in it then uncomment until I find the problematic piece of code.

I finally found that I was calling a function that used create_function from PHP. Many people are 'complaining' about 'memory leaks' from this function. The problem is not a memory leak but instead the fact that if you call the create_function in a loop, it will really create as many functions as the number of times you loop. To avoid this, I've found this concept to avoid recreating the function thousands of times.

<?php 
global $my_func; 
if (!isset($my_func)) { 
    $my_func = create_function($args, $code); 
}

$my_func(); 
?>

Adapting the code to make sure the function is created only once solved the problem. The whole script now takes only 8MB of memory instead of breaking after busting over 128MB.

Maxime
  • 7,283
  • 4
  • 48
  • 49