views:

426

answers:

5

Hi everybody,

Do you know any solution to recover from the PHP fatal error : "Allowed memory size ... exhausted"

I have a shutdown function that is called when a fatal error appear. This function create an ErrorException from it, and logs it.

The problem is : when there is no more memory available, it can't log the error (I log in Firebug, via FirePHP, with Zend Framework).

So what i mean by "how to recover from it", is how to perform basic error log, and let Zend Framework send the Headers, so that the error is logged (in Firebug in my case) as any other error ?

Thanks

A: 

PHP errors are sent by default to your apache error log /path/to/apache/logs/error.log and you can see it there.

nickf
No kidding ? Maybe I should stop writing PHP and create a MySpace.Did you read my post ? I log to various destinations, I can read the error, I can do a var_dump, but I don't want to, this is a professional website. I want to be able to log the error and flush the headers once this error appears.
Matthieu
*"The problem is : when there is no more memory available, it can't log the error"* It sounded like you wanted to log the error.
nickf
+2  A: 

This error is a fatal error - that means you cannot recover from it. If PHP has hit it's memory limit, it won't be able to allocate any more memory to create your exception and any other memory it needs to carry on its execution.

There is another type of error - "catchable fatal error" which as the name suggests, can be caught in a try/catch, but unfortunately the memory size allocation is not one of them.

Andy Shellam
Is that possible to expand the memory limit during the execution ? (just to get enough memory to finish the rendering of the site)I suppose this is not possible to list all the objects in memory, and "kill" the one that is too big, like I could with processes ? (I know this is asking for the moon, but who knows)
Matthieu
Don't believe so. If it's one particular thing that's running into this problem, then you might just have to avoid the issue and raise the memory limit (for that script). Which isn't what you're wanting, but I don't believe you have any other choice.
Blair McMillan
No 'fraid not. Just out of curiosity, how much is your current memory limit, and what sort of website is it? I'm not sure what the recommended amount is, but I tend to set it to 1/4 of the RAM on the machine. Perhaps at key points in your script you could call memory_get_usage and if it's getting high, increase the memory_limit setting before it trips? Not sure without knowing your script's layout and purpose.
Andy Shellam
Looking at the example on the manpage (http://www.php.net/manual/en/function.memory-get-usage.php) it looks like calling that function triggers the garbage collector, so maybe unsetting some un-needed variables before calling that function may help?
Andy Shellam
The limit is actually 128M. But currently I have about 10 Exceptions (that I know of, and that will be fixed, but until then they have no impact on the website) that are logged to Firebug via an exception handler. So maybe this is what is causing the memory usage (an Exception seems to be a very big object). If that is possible to extend the memory limit, i'll do so ? (just a bit, to flush the headers). The garbage collector seems a good idea too.
Matthieu
+1  A: 

The regular way to customize error handling is through

set_error_handler — Sets a user-defined error handler function

The docs for this function state (emphasis mine):

The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.

So, it won't work regularly, but you can try

Note: I have no clue if the latter two would work, so any feedback is appreciated.

Gordon
Yeah, this doesn't work for fatal errors (E_ERROR.)
Andy Shellam
register_shutdown_function is the solution I am currently using, and it works fine
Matthieu
@Matthieu Cool to know. Happy I could help.
Gordon
+1  A: 

One I can think of is that you when you're doing your memory intensive operation you manually query get_memory_usage() on a regular basis (e.g. every loop iteration) and dump out your headers/error when it goes over some failsafe value which is below the script limit. It will slow your script down a lot, but at least you'll get something back.

Or, and you may not be able to do this, run the memory intensive stuff as a CLI-based script called from inside your web-based stuff by using exec. The CLI part might fall over, but the web part will be able to report on it.

Mike
Thanks, I will check out the get_memory_usage() function, but I want a generic solution for this problem, this is not about a specific page that requires a lot of memory (I use CLI scripts, as you said, for that). So I can't check get_memory_usage() on a regular basis.
Matthieu
Oops, it's `memory_get_usage()`, has been ages since I used that one.
Mike
A: 

Got an idea for an untested trick and I'd be happy to know if it helped. Allocate some global variable when you first register the shutdown function and release it when the shutdown function's code is first executed. You may then have sufficient memory to create the Exception object. Let me know if it worked and please publish the code here.