I've got a handmade ORM in PHP that seems to be bumping up against an object limit and causing php to crash. Here's a simple script that will cause crashes:
<?
class Bob
{
protected $parent;
public function Bob($parent)
{
$this->parent = $parent;
}
public function __toString()
{
if($this->parent)
return (string) "x " . $this->parent;
return "top";
}
}
$bobs = array();
for($i = 1; $i < 40000; $i++)
{
$bobs[] = new Bob($bobs[$i -1]);
}
?>
Even running this from the command line will cause issues. Some boxes take more than 40,000 objects. I've tried it on Linux/Apache (fail) but my app runs on IIS/FastCGI. On FastCGI this causes the famous "The FastCGI process exited unexpectedly" error.
Obviously 20k objects is a bit high, but it crashes with far fewer objects if they have data and nested complexity.
Fast CGI isn't the issue - I've tried running it from the command line. I've tried setting the memory to something really high - 6,000MB and to something really low - 24MB. If I set it low enough I'll get the "allocated memory size xxx bytes exhausted" error.
I'm thinking that it has to do with the number of functions that are called - some kind of nesting prevention. I didn't think that my ORM's nesting was that complicated but perhaps it is. I've got some pretty clear cases where if I load just ONE more object it dies, but loads in under 3 seconds if it works.
Interestingly, in my environment, it appears that the segfault occurs when it comes time to deconstruct the objects -- code placed after the loop runs fine. It's only when PHP starts to shutdown that the segfault occurs.
You could file a bug, but you may find that PHP's maintainers won't go out of their way to support this sort of thing. I've seen at least one bug report about a memory leak in which the official response was essentially "Wontfix: memory is released after the page is rendered, so this doesn't really matter" -- effectively implying that uses outside of the simple case of rapidly rendering a webpage and terminating aren't really supported.
After 5 years of full-time PHP development, I've arrived at a simple rule: if it crashes PHP, don't do it. PHP has its limitations, and you'll find yourself most successful if you don't push those limits.
That means things like avoiding
create_function()
in PHP <=5.2 (it leaks memory like crazy). You can try to usecreate_function()
to use PHP as if it were a functional language. It's not, and you'll find it fails miserably if you try to use it as such.So if PHP chokes on nesting objects 40000 levels deep... don't nest objects 40000 levels deep. One possible alternative is using arrays instead of objects -- but that still sounds pretty heinous.