Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safely catch a 'Allowed memory size exhausted' error in PHP

Tags:

php

memory

I have a gateway script that returns JSON back to the client. In the script I use set_error_handler to catch errors and still have a formatted return.

It is subject to 'Allowed memory size exhausted' errors, but rather than increase the memory limit with something like ini_set('memory_limit', '19T'), I just want to return that the user should try something else because it used to much memory.

Are there any good ways to catch fatal errors?

like image 803
Matt R. Wilson Avatar asked Dec 09 '11 02:12

Matt R. Wilson


People also ask

How do I fix PHP fatal error allowed memory size?

The correct way is to edit your php. ini file. Edit memory_limit to your desire value. As from your question, 128M (which is the default limit) has been exceeded, so there is something seriously wrong with your code as it should not take that much.

How do I fix the allowed memory size 1610612736 bytes exhausted?

Try prefixing your command with COMPOSER_MEMORY_LIMIT=-1 . This will remove the memory limit for the execution of the command. Update: Memory exhaust errors should now be resolved by using Composer 2.


2 Answers

As this answer suggests, you can use register_shutdown_function() to register a callback that'll check error_get_last().

You'll still have to manage the output generated from the offending code, whether by the @ (shut up) operator, or ini_set('display_errors', false)

ini_set('display_errors', false);  error_reporting(-1);  set_error_handler(function($code, $string, $file, $line){         throw new ErrorException($string, null, $code, $file, $line);     });  register_shutdown_function(function(){         $error = error_get_last();         if(null !== $error)         {             echo 'Caught at shutdown';         }     });  try {     while(true)     {         $data .= str_repeat('#', PHP_INT_MAX);     } } catch(\Exception $exception) {     echo 'Caught in try/catch'; } 

When run, this outputs Caught at shutdown. Unfortunately, the ErrorException exception object isn't thrown because the fatal error triggers script termination, subsequently caught only in the shutdown function.

You can check the $error array in the shutdown function for details on the cause, and respond accordingly. One suggestion could be reissuing the request back against your web application (at a different address, or with different parameters of course) and return the captured response.

I recommend keeping error_reporting() high (a value of -1) though, and using (as others have suggested) error handling for everything else with set_error_handler() and ErrorException.

like image 157
Dan Lugg Avatar answered Sep 23 '22 11:09

Dan Lugg


If you need to execute business code when this error happens (logging, backup of the context for future debugs, emailing or such), registering a shutdown function is not enough: you should free memory in a way.

One solution is to allocate some emergency memory somewhere:

public function initErrorHandler() {     // This storage is freed on error (case of allowed memory exhausted)     $this->memory = str_repeat('*', 1024 * 1024);      register_shutdown_function(function()     {         $this->memory = null;         if ((!is_null($err = error_get_last())) && (!in_array($err['type'], array (E_NOTICE, E_WARNING))))         {            // $this->emergencyMethod($err);         }     });     return $this; } 
like image 25
Alain Tiemblo Avatar answered Sep 22 '22 11:09

Alain Tiemblo