Circular References
Circular-references has been a long outstanding issue with PHP. They are caused by the fact that PHP uses a reference counted memory allocation mechanism for its internal variables. This causes problems for longer running scripts (such as an Application Server or the eZ Components test-suite) as the memory is not freed until the end of the request. But not everybody is aware on what exactly the problem is, so here is a small introduction to circular references in PHP.
In PHP a refcount value is kept for every variable container (zval). Those containers are pointed to from a function's symbol table that contains the names of all the variables in the function's scope. Every variable, array element or object property that points to a zval will increase its refcount by one. The refcount of a zval container is decreased by one whenever call unset() on a variable name that points to it, or when a variable goes away because the function in which it was used ends. For a more thorough explanation about references, please see the article on this that I wrote for php|architect some time ago.
The problems with circular references all start by creating an array or an object:
<?php $tree = array( 'one' ); ?>
This creates the following structure in memory:
Now if we proceed to add a new element to the array, that points back to the array with:
<?php $tree[] = $tree; ?>
We create a circular reference like this:
As you can see there are two variable names pointing to the array itself. Once through the $tree variable, and once through the 2nd element of the array. Because there are two variable names pointing to the container, its refcount is 2.
Now, the next step that actually creates the problem if we unset() the $tree variable. As I mentioned before an unset() on a variable name will decrease the refcount of the variable container the variable points to, in this case the array value. The structure in memory now looks like this:
Note that there is no variable pointing to the array container anymore. Because of this PHP has no way of freeing this data anymore, and the memory leak is born. PHP however does remove all allocated variables at the end of each request, so it's not a hard-memory leak, but it's still annoying enough for long running scripts and daemons written in PHP.
Luckily there are a few solutions to this problem. The first one is to use a new garbage collection algorithm, another is to augment the reference counting system with some cyclic tracing . The latter solution is something that is currently undertaken by David Wang, one of the Google Summer of Code students. He mentioned he is making good progress and I can hardly wait until I can play with it :)
Comments
With MDB2, I ran into a situation where I needed circular references. MDB2 can be extended with modules. These module instances need to be attached to the mdb2 instance so that they can be used like so: $mdb2->manager->listTables();
The manager property stores the instance of the manager module.
Now obviously inside the manager module we need to be able to execute a query, which in turn requires that the manager module have a reference to the MDB2 instance. Bad, ugly etc.
So my solution is still not pretty, though I guess it could get cleaned up a bit by making more use of OO constructs. So what I do is that I actually store a reference to all MDB2 instances into a global array. In the constructor of all modules I do not pass in the MDB2 instance but instead I pass the key to the global array that points to the MDB2 instance. Of course this global array is cleaned up via a destructor.
Lukas: maybe you shoud make some kind of singleton, which would store references to those objects? I think Symfony does it this way (sfContext class)
also, you can add some kind of destructor to singleton, which would effectively deinitialize it, on user request…
Derick: yup. I am impatiently waiting to see the result of Davids work too.
But my other thought is, that in most cases one can easily solve problems without circular references, and in most cases they are the sign of bad design
Actually I am already leveraging this global array to provide a "singleton". I put that in quotes, because you might obviously require access to multiple different database at the same time. However for the purposes I described, its a lot more performat and reliable to use the approach I described instead of going through the normal singlaton end user API I also provide.
Great to hear that.. I'm tired of manually calling __destruct() methods :)
Life Line
Put new open stretch of Canterbury Road on map
Created a bench and a crossing
Created 2 benches and a crossing; Updated 5 cushions, a post_box, and a crossing
Created a crossing; Updated a cushion
If you were wondering whether the www.php.net & downloads.php.net services weren't responding very well in the last 6 hours — thousands of requests/sec to https://www.php.net/ 's root.
The server's load was 720, didn't die, but CDN connections to it timed out.
Now there is a caching strategy in place for a selected set of resources.
Updated a bench
Created 3 benches; Updated 10 benches
Updated a bench
Updated a bus_stop
Created a bench and a waste_basket; Updated 6 bus_stops and a crossing
Created 2 waste_baskets and a recycling; Updated 2 bicycle_parkings and a recycling
Updated a fast_food, a funeral_directors shop, and 2 other objects; Confirmed a fast_food and a hairdresser shop
Created an information; Updated 3 benches and 2 waste_baskets
Updated 2 benches and a waste_basket
Updated a bench
Created a waste_basket and an information
Created a waste_basket
I hiked 18.0km in 4h1m52s
I walked 1.4km in 17m19s
I walked 4.5km in 1h21m49s
I just made and ate, a bowl full of bacon fried Brussels Sprouts. Not under duress, and out of my own free will.
Added new residential building
Created a hairdresser shop; Confirmed a convenience shop and a dry_cleaning shop
Created a building_materials shop, a vacant shop, and 4 other objects; Confirmed a hairdresser shop, a cafe, and 2 other objects



Shortlink
This article has a short URL available: https://drck.me/cr-5li