When I began a recent project writing a PHP cli program (a worker process for a queue system), I assumed that PHP 7 would occasionally run garbage collection. This seemed logical to me as without it the long running script I was writing would constantly hit the memory limit and crash.
As you can probably guess, this assumption turned out to be wrong. Without specific instructions to the contrary, garbage simply continues to accumulate and eventually the crash occurs.
Singling out the problem
These two code snippets illustrate this at the simplest level. The first script calls gc_collect_cycles() manually and doesn’t crash, the second script does crash.
As you can see, when you don’t call gc_collect_cycles it never happens, you get to the memory limit and PHP kills itself.
Here’s the code I used to ‘waste’ memory, it purposefully creates cyclic references that can only be cleaned by the garbage collector. Note that without these cycles the objects will be cleaned by reference counting as soon as they fall out of scope.
It’s a bug
PHP doesn’t even GC itself at the moment when it’s about to cause itself to crash. It seems like a bug and I’m certainly not alone in thinking so (here’s the same issue on the PHP bug tracker #60982). In the PHP-DEV mailing list however some of the reasoning behind this behaviour is discussed in more detail.
The limitations of PHP’s current way of handling this are recognised and the suggested reasoning is mostly down to complications running __destruct methods that require memory, when the memory limit has already been reached.
Perhaps it’s something that can be rectified in future as suggested in the mailing list by use of a soft and hard memory limit. For now though, we’re left doing manual garbage collection using gc_collect_cycles.
This article was originally posted as a stack overflow question.