#48781 [NEW]: Cyclical garbage collector memory leak

[email protected] ("nate at frickenate dot com")
Newsgroups php.bugs
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.