How do you debug php "Out of Memory" problems?

Recently, I had some problems with PHP memory limits:

Out of memory (22544384 allocated) (tried to allocate 232 bytes)

This is pretty unpleasant for debugging, since I did not have much information left about what caused the problem.

Adding a shutdown function helped

register_shutdown_function('shutdown'); 

then using error_get_last (); I can get information about the last error, in this case the fatal error "Out of memory", such as line number and php file name.

This is good and all, but my php program is highly object oriented. The depth of the error in the stack does not tell me about the control structure or the execution stack at the time of the error. I tried debug_backtrace (), but it just shows me the stack during shutdown, not the stack during error.

I know that I can just raise the memory limit with ini_set or change php.ini, but that doesn’t bring me closer to understanding what consumes so much memory or what my thread of execution looks like during an error.

Does anyone have a good methodology for debugging memory errors in advanced object-oriented PHP programs?

+25
source share
6 answers
 echo '<pre>'; $vars = get_defined_vars(); foreach($vars as $name=>$var) { echo '<strong>' . $name . '</strong>: ' . strlen(serialize($var)) . '<br />'; } exit(); /* ... Code that triggers memory error ... */ 

I use this to print a list of assigned variables just before the problems section of my code, as well as a (very) rough estimate of the size of the variable. I come back and unset everything that is not needed on and outside of interest.

Useful when installing an extension is not an option.

You can modify the code above to use memory_get_usage in such a way as to give you a different estimate of the memory in the variable, not sure if it will be better or worse.

+9
source

Memprof is a php extension that helps locate these pieces of memory, especially in object-oriented codes.

This adapted tutorial is very useful.

Note. I tried unsuccessfully to compile this extension for windows. If you try to do this, make sure your php is not thread safe. To avoid some headaches, I suggest you use it in * nix environments.

Another interesting link was slideshare , describing how php handles memory. This gives you some tips regarding the use of a memory script.

+7
source

Interestingly, perhaps your thinking considers the methodology to be corrupted.

The main answer to your question is how to find out where this error occurs. - an answer has already been given; you know what that means.

However, this is one of those cases where a startup error is not a problem - of course, this 232-byte object is not your problem at all. These are the 20+ Megs that were allocated before it.

Several ideas have been posted to help you keep track of this; you really need to look at a "higher level" here in the application architecture, not just the individual functions.

Perhaps your application requires more memory to do what it does with custom loading. Or it may happen that there are some real memory bots that are not needed - but you must know what is necessary or not to answer this question.

Basically, this means that you need to take turns, by object, to profile as needed until you find what you are looking for; large memory users. Note that there cannot be one or two large objects ... if it were that simple! Once you find memory pigs, you need to find out if they can be optimized. If not, you will need more memory.

+6
source

Check the documentation of the memory_get_usage () function to see the memory usage at runtime.

+3
source

Website IF! 1 0 "provides an easy-to-use MemoryUsageInformation class. This is very useful for debugging memory leaks.

 <?php class MemoryUsageInformation { private $real_usage; private $statistics = array(); // Memory Usage Information constructor public function __construct($real_usage = false) { $this->real_usage = $real_usage; } // Returns current memory usage with or without styling public function getCurrentMemoryUsage($with_style = true) { $mem = memory_get_usage($this->real_usage); return ($with_style) ? $this->byteFormat($mem) : $mem; } // Returns peak of memory usage public function getPeakMemoryUsage($with_style = true) { $mem = memory_get_peak_usage($this->real_usage); return ($with_style) ? $this->byteFormat($mem) : $mem; } // Set memory usage with info public function setMemoryUsage($info = '') { $this->statistics[] = array('time' => time(), 'info' => $info, 'memory_usage' => $this->getCurrentMemoryUsage()); } // Print all memory usage info and memory limit and public function printMemoryUsageInformation() { foreach ($this->statistics as $satistic) { echo "Time: " . $satistic['time'] . " | Memory Usage: " . $satistic['memory_usage'] . " | Info: " . $satistic['info']; echo "\n"; } echo "\n\n"; echo "Peak of memory usage: " . $this->getPeakMemoryUsage(); echo "\n\n"; } // Set start with default info or some custom info public function setStart($info = 'Initial Memory Usage') { $this->setMemoryUsage($info); } // Set end with default info or some custom info public function setEnd($info = 'Memory Usage at the End') { $this->setMemoryUsage($info); } // Byte formatting private function byteFormat($bytes, $unit = "", $decimals = 2) { $units = array('B' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4, 'PB' => 5, 'EB' => 6, 'ZB' => 7, 'YB' => 8); $value = 0; if ($bytes > 0) { // Generate automatic prefix by bytes // If wrong prefix given if (!array_key_exists($unit, $units)) { $pow = floor(log($bytes) / log(1024)); $unit = array_search($pow, $units); } // Calculate byte value by prefix $value = ($bytes / pow(1024, floor($units[$unit]))); } // If decimals is not numeric or decimals is less than 0 // then set default value if (!is_numeric($decimals) || $decimals < 0) { $decimals = 2; } // Format output return sprintf('%.' . $decimals . 'f ' . $unit, $value); } } 
+3
source

Use xdebug to use memory in the profile.

0
source

All Articles