ID: 36482 User updated by: K dot Londenberg at librics dot de Reported By: K dot Londenberg at librics dot de Status: Open Bug Type: Scripting Engine problem Operating System: Linux 2.6.12-1-386 PHP Version: 5.1.2 New Comment:
By accident, I posted the *working* version as example code. To provoke the bug, you need to uncomment the line containing "$bigd->subdata->subdata = $bigd;" Previous Comments: ------------------------------------------------------------------------ [2006-02-21 20:30:18] K dot Londenberg at librics dot de Description: ------------ The PHP Garbage Collector fails to free objects which are unreachable if they contain circular references to each other. The example script does not provoke an out of memory error, but I have some cases where a script hits the memory limit, even if there are loads of unreachable objects to be finalized. Sorry, but the example code has 32 lines. I guess it won't break your big repository anyway. Compare what happens if you run the example script as it is, and what happens if you uncomment the line containing "$bigd->subdata->subdata = $bigd;" If you want to test this script in a PHP Engine without large memory limits, just lower the numbers. BTW - this is a real problem and does happen quite frequently. All you need is some kind of circular reference between some objects, and everything referenced by those objects won't be cleared by the Garbage Collector until script termination. Reproduce code: --------------- <?php // This Test case demonstrates a bug where the PHP Garbage Collector fails // to release objects which are unreachable but contain circular references. class bigdata { private $data; public $subdata; public function __construct($entries) { $this->data = array(); echo "Creating BIGDATA with $entries entries\n"; if ($entries>=1000) { $this->subdata = new bigdata($entries/2); } for ($i=0;$i<$entries;$i++) { $this->data[] = $i; } } public function __destruct() { echo "Destroyed BIGDATA with ".count($this->data)." entries\n"; } } echo "<PRE>"; echo "Creating bigdata\n";flush(); $bigd = new bigdata(1000); echo "Removing reference to bigdata\n";flush(); $bigd = null; echo "Creating new bigdata\n";flush(); $bigd = new bigdata(1000); echo "Creating circular reference. \n";flush(); //$bigd->subdata->subdata = $bigd; // If you omit this statement, the Gargabe collector will destroy everything as it should. echo "Removing all global references to bigdata\n";flush(); $bigd = null; echo "Now, exiting\n";flush(); exit; ?> Expected result: ---------------- <PRE>Creating bigdata Creating BIGDATA with 1000 entries Creating BIGDATA with 500 entries Removing reference to bigdata Destroyed BIGDATA with 1000 entries Destroyed BIGDATA with 500 entries Creating new bigdata Creating BIGDATA with 1000 entries Creating BIGDATA with 500 entries Creating circular reference. Removing all global references to bigdata Destroyed BIGDATA with 1000 entries Destroyed BIGDATA with 500 entries Now, exiting Actual result: -------------- <PRE>Creating bigdata Creating BIGDATA with 1000 entries Creating BIGDATA with 500 entries Removing reference to bigdata Destroyed BIGDATA with 1000 entries Destroyed BIGDATA with 500 entries Creating new bigdata Creating BIGDATA with 1000 entries Creating BIGDATA with 500 entries Creating circular reference. Removing all global references to bigdata Now, exiting Destroyed BIGDATA with 1000 entries Destroyed BIGDATA with 500 entries ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=36482&edit=1