#48781 [NEW]: Cyclical garbage collector memory leak

From: Date: Thu, 02 Jul 2009 18:35:43 +0000
Subject: #48781 [NEW]: Cyclical garbage collector memory leak
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-139160@lists.php.net to get a copy of this message
From: nate at frickenate dot com Operating system: Debian 5.0 kernel 2.6.24-23-xen PHP version: 5.3.0 PHP Bug Type: Performance problem Bug description: Cyclical garbage collector memory leak Description: ------------ The new cyclical garbage collector isn't collecting everything it should be - somewhere there is a memory leak. The issue I am bringing up is not about delayed collection - this is a true memory leak with memory that is never reclaimed. When a variable (in this example, $user) contains an object with a cyclical reference, there is a small amount of memory that is leaked/not reclaimed when you set $user to another object (of any class). If you set $user to an int/string/boolean/null before setting $user to another object, all memory is collected properly. I came to the conclusion that this must be a problem with the garbage collector, since if you replace the "$this->user = $user;" with "$this->user = new StdClass;" (thus preventing the creation of a cyclical reference), the leak goes away. So basically right now: <?php while ($user = get_next_user()) { // do stuff with $user // php bug: have to unset before next iteration // to prevent memory leak caused by buggy gc unset($user); } ?> Reproduce code: --------------- <?php /* How to use: a) run test 1 by running code as-is b) run test 2 by commenting out test 1, uncomment test 2 c) run test 3 by commenting out test 1 & 2, uncomment test 3 */ class User { protected $profile; public function __construct () { $this->profile = new UserProfile($this); } } class UserProfile { private $user; public function __construct ($user) { $this->user = $user; } } for ($userid = 1; ; $userid++) { $user = new User; if ($userid % 100000 == 0) printf("memory usage after %s users: %s MB.\n", number_format($userid), number_format(memory_get_usage() / 1024 / 1024, 2)); // TEST 1 - do nothing before we set the // new User on next iteration of the loop). // RESULT: leaks memory (see "Actual result" section) continue; // TEST 2 - set $user to an empty object, before // we set the new User on next iteration // RESULT: leaks memory (see "Actual result" section) //$user = new StdClass; continue; // TEST 3 - set $user to anything other than an object, // before we set the new User on next iteration. // RESULT: does NOT leak memory (see "Expected result" section) //$user = 'not an object'; continue; } ?> Expected result: ---------------- memory usage after 100,000 users: 1.54 MB. memory usage after 200,000 users: 1.54 MB. memory usage after 300,000 users: 1.54 MB. memory usage after 400,000 users: 1.54 MB. memory usage after 500,000 users: 1.54 MB. memory usage after 600,000 users: 1.54 MB. memory usage after 700,000 users: 1.54 MB. memory usage after 800,000 users: 1.54 MB. memory usage after 900,000 users: 1.54 MB. memory usage after 1,000,000 users: 1.54 MB. [snip] memory usage after 99,000,000 users: 1.54 MB. memory usage after 99,100,000 users: 1.54 MB. memory usage after 99,200,000 users: 1.54 MB. memory usage after 99,300,000 users: 1.54 MB. memory usage after 99,400,000 users: 1.54 MB. memory usage after 99,500,000 users: 1.54 MB. memory usage after 99,600,000 users: 1.54 MB. memory usage after 99,700,000 users: 1.54 MB. memory usage after 99,800,000 users: 1.54 MB. memory usage after 99,900,000 users: 1.54 MB. memory usage after 100,000,000 users: 1.54 MB. Actual result: -------------- memory usage after 100,000 users: 1.55 MB. memory usage after 200,000 users: 1.57 MB. memory usage after 300,000 users: 1.58 MB. memory usage after 400,000 users: 1.59 MB. memory usage after 500,000 users: 1.61 MB. memory usage after 600,000 users: 1.62 MB. memory usage after 700,000 users: 1.64 MB. memory usage after 800,000 users: 1.65 MB. memory usage after 900,000 users: 1.66 MB. memory usage after 1,000,000 users: 1.68 MB. [snip] memory usage after 99,000,000 users: 18.43 MB. memory usage after 99,100,000 users: 18.44 MB. memory usage after 99,200,000 users: 18.46 MB. memory usage after 99,300,000 users: 18.47 MB. memory usage after 99,400,000 users: 18.48 MB. memory usage after 99,500,000 users: 18.50 MB. memory usage after 99,600,000 users: 18.51 MB. memory usage after 99,700,000 users: 18.53 MB. memory usage after 99,800,000 users: 18.54 MB. memory usage after 99,900,000 users: 18.55 MB. memory usage after 100,000,000 users: 18.57 MB. -- Edit bug report at http://bugs.php.net/?id=48781&edit=1 -- Try a CVS snapshot (PHP 5.2): http://bugs.php.net/fix.php?id=48781&r=trysnapshot52 Try a CVS snapshot (PHP 5.3): http://bugs.php.net/fix.php?id=48781&r=trysnapshot53 Try a CVS snapshot (PHP 6.0): http://bugs.php.net/fix.php?id=48781&r=trysnapshot60 Fixed in CVS: http://bugs.php.net/fix.php?id=48781&r=fixedcvs Fixed in CVS and need be documented: http://bugs.php.net/fix.php?id=48781&r=needdocs Fixed in release: http://bugs.php.net/fix.php?id=48781&r=alreadyfixed Need backtrace: http://bugs.php.net/fix.php?id=48781&r=needtrace Need Reproduce Script: http://bugs.php.net/fix.php?id=48781&r=needscript Try newer version: http://bugs.php.net/fix.php?id=48781&r=oldversion Not developer issue: http://bugs.php.net/fix.php?id=48781&r=support Expected behavior: http://bugs.php.net/fix.php?id=48781&r=notwrong Not enough info: http://bugs.php.net/fix.php?id=48781&r=notenoughinfo Submitted twice: http://bugs.php.net/fix.php?id=48781&r=submittedtwice register_globals: http://bugs.php.net/fix.php?id=48781&r=globals PHP 4 support discontinued: http://bugs.php.net/fix.php?id=48781&r=php4 Daylight Savings: http://bugs.php.net/fix.php?id=48781&r=dst IIS Stability: http://bugs.php.net/fix.php?id=48781&r=isapi Install GNU Sed: http://bugs.php.net/fix.php?id=48781&r=gnused Floating point limitations: http://bugs.php.net/fix.php?id=48781&r=float No Zend Extensions: http://bugs.php.net/fix.php?id=48781&r=nozend MySQL Configuration Error: http://bugs.php.net/fix.php?id=48781&r=mysqlcfg

« previous php.bugs (#139160) next »