One of the great benefits of using scripting languages is that you can take advantage of the automatic garbage collection mechanism it has (freeing up memory). You don't need to do any free memory processing after using the variable, PHP will help you complete it.
Of course, we can call the unset () function to free up memory as we wish, but this is not usually necessary.
In PHP, however, there is at least one situation where memory is not automatically released, even if it is manually invoked unset (). Details can be tested: http://bugs.php.net/bug.php?id=33595.
Problem symptom
If two objects have a cross-reference relationship, such as "Parent object-child object", calling Unset () on the parent object does not release the memory that references the parent object in the child object (even if the parent object is garbage collected).
A little confused? Let's look at the following code:
<?php
Class Foo {
function __construct ()
{
$this->bar = new Bar ($this);
}
}
Class Bar {
function __construct ($foo = null)
{
$this->foo = $foo;
}
}
while (true) {
$foo = new Foo ();
Unset ($foo);
Echo Number_format (Memory_get_usage ()). "\ n";
}
?>
Run this code and you'll see that the memory usage is getting higher and higher until the light runs out.
...
33,551,616
33,551,976
33,552,336
33,552,696
PHP Fatal Error: allowed memory size of 33554432 bytes exhausted
(tried to allocate bytes) in memleak.php of line 17
This is not a problem for most PHP programmers.
But if you use a lot of references in a long-running code, especially if the object is relatively large, the memory will run out quickly.
Userland Solutions
Although somewhat tedious and not elegant, a solution is provided in the previously mentioned bugs.php.net link.
This scheme uses a destructor method to achieve the goal before releasing the object. The destructor method clears all internal parent object references, which means that the portion of memory that would otherwise overflow can be freed.
Here is the code after "fix":
<?php
Class Foo {
function __construct ()
{
$this->bar = new Bar ($this);
}
function __destruct ()
{
unset ($this->bar);
}
}
Class Bar {
function __construct ($foo = null)
{
$this->foo = $foo;
}
}
while (true) {
$foo = new Foo ();
$foo->__destruct ();
Unset ($foo);
Echo Number_format (Memory_get_usage ()). "\ n";
}
?>
Note the new Foo::__destruct () method, and the call to $foo->__destruct () before the object is disposed. Now that the code solves the problem of increasing memory usage, the code can work well.
PHP kernel solution?
Why is there a memory overflow happening? My research on the PHP kernel is not proficient, but it is certain that the problem is related to the reference count.
Reference counts that reference $foo in the $bar are not decremented because the parent object $foo released, and PHP thinks you still need $foo object and will not release this part of the memory ... That's probably it.
It is true to see my ignorance, but the general meaning is that a reference count does not decrease, so some memory will never be released.
In the Bugs.php.net link mentioned earlier, I see that the process of modifying garbage collection will sacrifice great performance because I don't know much about reference counting, so I think it's true.
Rather than changing the process of garbage collection, why not unset () the task of releasing internal objects? (or call __destruct () when you release the object?) )
Perhaps the PHP kernel developer can make changes to this garbage collection mechanism here and elsewhere.
Update: Martin Fjordvald in the comments about a patch written by David Wang for garbage collection (it looks more like "a piece of cloth")-Very large. See the CVS export information at the end of this message for details. Does exist (a message) and is being watched by members of the PHP kernel developers. The problem is that the patch doesn't get too much support in the PHP5.3. I think a good compromise is to call the __destruct () method in the object in the unset () function;