note 105368 added to language.oop5.decon
| From: | david dot scourfield at llynfi dot co dot uk | Date: | Fri, 12 Aug 2011 11:17:37 +0000 |
| Subject: | note 105368 added to language.oop5.decon | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-182440@lists.php.net to get a copy of this message | ||
Be aware of potential memory leaks caused by circular references within objects. The PHP manual
states "[t]he destructor method will be called as soon as all references to a particular object
are removed" and this is precisely true: if two objects reference each other (or even if one
object has a field that points to itself as in $this->foo = $this) then this reference will
prevent the destructor being called even when there are no other references to the object at all.
The programmer can no longer access the objects, but they still stay in memory.
Consider the following example:
<?php
header("Content-type: text/plain");
class Foo {
/**
* An indentifier
* @var string
*/
private $name;
/**
* A reference to another Foo object
* @var Foo
*/
private $link;
public function __construct($name) {
$this->name = $name;
}
public function setLink(Foo $link){
$this->link = $link;
}
public function __destruct() {
echo 'Destroying: ', $this->name, PHP_EOL;
}
}
// create two Foo objects:
$foo = new Foo('Foo 1');
$bar = new Foo('Foo 2');
// make them point to each other
$foo->setLink($bar);
$bar->setLink($foo);
// destroy the global references to them
$foo = null;
$bar = null;
// we now have no way to access Foo 1 or Foo 2, so they OUGHT to be __destruct()ed
// but they are not, so we get a memory leak as they are still in memory.
//
// Uncomment the next line to see the difference when explicitly calling the GC:
// gc_collect_cycles();
//
// see also: http://www.php.net/manual/en/features.gc.php
//
// create two more Foo objects, but DO NOT set their internal Foo references
// so nothing except the vars $foo and $bar point to them:
$foo = new Foo('Foo 3');
$bar = new Foo('Foo 4');
// destroy the global references to them
$foo = null;
$bar = null;
// we now have no way to access Foo 3 or Foo 4 and as there are no more references
// to them anywhere, their __destruct() methods are automatically called here,
// BEFORE the next line is executed:
echo 'End of script', PHP_EOL;
?>
This will output:
Destroying: Foo 3
Destroying: Foo 4
End of script
Destroying: Foo 1
Destroying: Foo 2
But if we uncomment the gc_collect_cycles(); function call in the middle of the script, we get:
Destroying: Foo 2
Destroying: Foo 1
Destroying: Foo 3
Destroying: Foo 4
End of script
As may be desired.
NOTE: calling gc_collect_cycles() does have a speed overhead, so only use it if you feel you need
to.
----
Server IP: 69.147.83.197
Probable Submitter: 217.64.124.225
----
Manual Page -- http://www.php.net/manual/en/language.oop5.decon.php
Edit -- https://master.php.net/note/edit/105368
Del: integrated -- https://master.php.net/note/delete/105368/integrated
Del: useless -- https://master.php.net/note/delete/105368/useless
Del: bad code -- https://master.php.net/note/delete/105368/bad+code
Del: spam -- https://master.php.net/note/delete/105368/spam
Del: non-english -- https://master.php.net/note/delete/105368/non-english
Del: in docs -- https://master.php.net/note/delete/105368/in+docs
Del: other reasons-- https://master.php.net/note/delete/105368
Reject -- https://master.php.net/note/reject/105368
Search -- https://master.php.net/manage/user-notes.php