Reputation: 1984
This relates to a PHP 5.3 Cli application that processes a lot of data in a complex way, taking hours to run. Someone discovered that turning off garbage collection made it run a great deal faster (maybe as much as 50%).
The only article I've come across that mentions this performance hit is http://derickrethans.nl/collecting-garbage-performance-considerations.html. I'm not sure I follow it entirely, but it seems to suggest that it only applies to code with a lot of circular references.
Could someone shed some light on this please?
Also, given that we have turned gc off, is there any way to manually reduce memory? Using unset() has been suggested. A quick test has shown that eighty or so bytes is freed by unset() regardless of the size of the object. This suggests it's just unsetting the reference, which is borne out by what I have read online. Am I right in thinking that these eighty bytes would be freed anyway, even without garbage collection, when the variable falls out of scope?
Upvotes: 7
Views: 1443
Reputation: 57719
You can manually remove cycles from your code by using unset
. You clean up cycles from classes by implementing a __destruct
function. unset
all private, protected or public variables that reference other Objects.
It gets really tedious if you're applying this to an existing program but it is doable.
class A {
public $ref;
public function __destruct() {
unset($this->ref);
echo "destruct";
}
}
$a1 = new A();
$a2 = new A();
$a1->ref = $a2;
$a2->ref = $a1;
This does not work:
unset($a1, $a2);
echo "--";
// prints --destructdestruct (in 5.3)
This works:
$a1->__destruct();
unset($a1, $a2);
echo "--";
// prints destructdestructdestruct-- (in 5.3)
Upvotes: 2
Reputation: 131881
You just disabled the circular-reference-GC. The regular one still works.
The common GC tests, whether or not there are zval
s ("memory"), that are not referenced by any variables, or properties anymore, and will free this memory. A circular reference is, when two or more objects references each other directly, or indirectly
$a = new stdClass;
$b = new stdClass;
$a->b = $b;
$b->a = $a;
unset($a, $b);
Now both objects reference each other, but they are both not referenced from anywhere else, so they are unreachable. This is, what the circular-reference GC tries to detect, but to find them, it iterates over every known object and finds out, if there is a reference "from outside". Its a little bit more complicated, but simplified thats it ;) So in structures with many references, espcially circular ones, it is a huge task.
Worth to mention: With unset()
you only remove the reference, but don't free the memory (directly). This is done by the GC later (and it makes a good job :))
Upvotes: 5