PHP, like most modern languages, has a garbage collection mechanism. It is supposed to destroy objects and variables as soon as there are no references to it anymore. To learn more about how it actually works, read this article. To summarize, PHP’s garbage handling is dumb, so any object that contains a circular reference will never be cleaned up.
Normally, this doesn’t matter because a typical PHP request only takes a short amount of time and creates only a few objects. But, lately I have been helping MikeT with a project he is working on. In this project, a request sometimes takes over 10s and creates close to 30,000 objects. The majority of these objects have circular references ….
Needless to say, memory usage was being destroyed by PHP. A single request would use around 90MB of memory. Even though PHP would clean up some of the memory after the request finished, there was still a large portion that wouldn’t be. This is completely unacceptable because a production server will run out of physical memory in a few minutes or less, start swapping, and eventually crash before FastCGI ever restarts the PHP process.
The solution was pretty simple but annoying. Basically, you have to write a custom destroy function that will unset all circular references. The __destruct() function can’t be used because it is only called when there are no more references to an object. After implementing a custom destroy function, memory usage per request dropped to about 16MB, which is a much more acceptable number. So, even though garbage handling is nice, anytime you have circular references, creating a custom destroy function to do your own memory management is probably a good idea.