Safe Detection of Allowed Memory Error

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 prone to "Allowed memory sizes" errors, and does not increase the memory limit with ini_set ('memory_limit', '19T'). I just want to return that the user should try something else, because he used a lot of memory.

Are there any good ways to detect fatal errors?

+63
php memory
Dec 09 2018-11-11T00:
source share
4 answers

Like this answer , you can use register_shutdown_function() to register a callback that will check error_get_last() .

You still have to control the output generated due to code violation, regardless of 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'; } 

At startup, the outputs are Caught at shutdown . Unfortunately, an ErrorException not ErrorException because a fatal error triggers the completion of the script, subsequently falling into the shutdown function only.

You can check the $error array in the shutdown function to get detailed information about the reason and respond accordingly. One sentence could re-send the request back to your web application (at a different address or with different parameters) and return the captured response.

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

+47
Dec 09 '11 at 3:45
source share

If you need to execute a business code when this error occurs (logging, backing up context for future debugs, sending by e-mail or the like), registering the shutdown function is not enough: you must free some memory.

One solution is to allocate some kind of 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; } 
+34
Dec 20 '14 at 16:05
source share

with this function you can get the size of the memory already occupied by the process, with the documentation memory_get_peak_usage. Documentation http://www.php.net/manual/en/function.memory-get-peak-usage.php . I think it would be easier if you could add a condition to redirect or stop the process before the process reaches the memory limit. :)

+7
Dec 09 '11 at 2:59 a.m.
source share

Although @ alain-tiemblo's solution works fine, I put this script in to show how you can reserve some of the memory in a php script outside the scope of the object.

Short version

 // memory is an object and it is passed by reference function shutdown($memory) { // unsetting $memory does not free up memory // I also tried unsetting a global variable which did not free up the memory unset($memory->reserve); } $memory = new stdClass(); // reserve 3 mega bytes $memory->reserve = str_repeat('❤', 1024 * 1024); register_shutdown_function('shutdown', $memory); 

Full sample script

 <?php function getMemory(){ return ((int) (memory_get_usage() / 1024)) . 'KB'; } // memory is an object and it is passed by reference function shutdown($memory) { echo 'Start Shut Down: ' . getMemory() . PHP_EOL; // unsetting $memory does not free up memory // I also tried unsetting a global variable which did not free up the memory unset($memory->reserve); echo 'End Shut Down: ' . getMemory() . PHP_EOL; } echo 'Start: ' . getMemory() . PHP_EOL; $memory = new stdClass(); // reserve 3 mega bytes $memory->reserve = str_repeat('❤', 1024 * 1024); echo 'After Reserving: ' . getMemory() . PHP_EOL; unset($memory); echo 'After Unsetting: ' . getMemory() . PHP_EOL; $memory = new stdClass(); // reserve 3 mega bytes $memory->reserve = str_repeat('❤', 1024 * 1024); echo 'After Reserving again: ' . getMemory() . PHP_EOL; // passing $memory object to shut down function register_shutdown_function('shutdown', $memory); 

And the result will be:

 Start: 349KB After Reserving: 3426KB After Unsetting: 349KB After Reserving again: 3426KB Start Shut Down: 3420KB End Shut Down: 344KB 
+5
Jun 07 '18 at 17:52
source share



All Articles