| Newsgroups |
php.bugs |
| Message-ID |
<[email protected]> |
Edit report at http://bugs.php.net/bug.php?id=48781&edit=1
ID: 48781
Comment by: [email protected]
Reported by: nate at frickenate dot com
Summary: Cyclical garbage collector memory leak
Status: Assigned
Type: Bug
Package: Scripting Engine problem
Operating System: Debian 5.0 kernel 2.6.24-23-xen
PHP Version: 5.3.0
Assigned To: dmitry
New Comment:
That should have said ...
"So, it is _NOT_ completely losing the items, just not cleaning them
during the
cycle. At shutdown, they are cleaned."
Previous Comments:
------------------------------------------------------------------------
[2010-04-19 12:31:56] [email protected]
If the loop is limited to 11111 items, using my code to report the
construct/use/destruct, the log ends with ...
11108:#3
11109:#3
11110:#3
11111:#3
04999:#3
09999:#3
10000:#3
So, it is completely losing the items, just not cleaning them during the
cycle.
At shutdown, they are cleaned.
------------------------------------------------------------------------
[2010-04-19 12:27:12] [email protected]
The gc cycle seems to miss the last 2 items on this cycle, but picks up
from the
last one for the next cycle, so is only actually dropping 1 item per
cycle.
My cycle goes something like this ...
Create and assign #1 to #4999
Create #5000
Destroy #1 to #4998
Assign #5000
Create and assign #5001 to #9999
Create #10000
Destroy #5000 to #9998 --- Skipped #4999
Assign #10000
Create and assign #10001 to #14999
Create #15000
Destroy #10000 to #14998 --- Skipped #9999
etc.
My code changes ...
class User {
protected
$profile, $usercount;
public function __construct ($usercount) {
echo str_pad($this->usercount = $usercount, 5, '0', STR_PAD_LEFT),
':#1',
PHP_EOL;
$this->profile = new UserProfile($this);
}
public function __destruct() {
echo str_pad($this->usercount, 5, '0', STR_PAD_LEFT), ':#3',
PHP_EOL;
}
}
class UserProfile {
private
$user;
public function __construct ($user) {
$this->user = $user;
}
}
for ($userid = 1; ; $userid++) {
$user = new User($userid);
echo str_pad($userid, 5, '0', STR_PAD_LEFT), ':#2', PHP_EOL;
// Same code as provided by Nate.
------------------------------------------------------------------------
[2010-04-19 09:54:39] [email protected]
Yeah. I confirm the problem. It looks like on each 100,000 iterations
PHP runs GC about 12 times. And on each GC run it looses 2 objects
referenced by $user. I'll try to fix it.
------------------------------------------------------------------------
[2010-04-18 02:28:35] [email protected]
I am unable to duplicate this behaviour using 5.3.2. The code given
below consistently uses 0.65 MB even up to 10 million iterations - I
pasted the output of up to 6 million, with the extended GC reporting
turned on:
<?php
class User {
protected $profile;
public function __construct () {
$this->profile = new UserProfile($this);
}
public function dispose() {
$this->profile->dispose();
$this->profile = null;
}
}
class UserProfile {
private $user;
public function __construct ($user) {
$this->user = $user;
}
public function dispose() {
$this->user = null;
}
}
for ($userid = 1; ; $userid++) {
if(isset($user)) {
$user->dispose();
}
$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));
continue;
}
?>
memory usage after 100,000 users: 0.65 MB.
memory usage after 200,000 users: 0.65 MB.
memory usage after 300,000 users: 0.65 MB.
[snip]
memory usage after 5,700,000 users: 0.65 MB.
memory usage after 5,800,000 users: 0.65 MB.
memory usage after 5,900,000 users: 0.65 MB.
GC Statistics
-------------
Runs: 0
Collected: 0
Root buffer length: 0
Root buffer peak: 9
Possible Remove from Marked
Root Buffered buffer grey
-------- -------- ----------- ------
ZVAL 16 7 7 0
ZOBJ 77999984 11999998 11999998 0
------------------------------------------------------------------------
[2010-01-05 19:31:01] nightstorm at tlen dot pl
I confirm, there is a true memory leak. Consider the following script,
where the references are unmounted manually with an extra dispose()
method:
~~~~
<?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);
}
public function dispose()
{
$this->profile->dispose();
$this->profile = null;
} // end dispose();
}
class UserProfile {
private
$user;
public function __construct ($user) {
$this->user = $user;
}
public function dispose()
{
$this->user = null;
} // end dispose();
}
for ($userid = 1; ; $userid++) {
if(isset($user))
{
$user->dispose();
}
$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));
continue;
}
~~~~~
In this case the result is still the same (PHP 5.3.1):
~~~~
memory usage after 100,000 users: 0.61 MB.
memory usage after 200,000 users: 0.61 MB.
memory usage after 300,000 users: 0.61 MB.
memory usage after 400,000 users: 0.61 MB.
memory usage after 500,000 users: 0.61 MB.
memory usage after 600,000 users: 0.61 MB.
memory usage after 700,000 users: 0.61 MB.
memory usage after 800,000 users: 0.61 MB.
memory usage after 900,000 users: 0.61 MB.
memory usage after 1,000,000 users: 0.61 MB.
memory usage after 1,100,000 users: 0.61 MB.
memory usage after 1,200,000 users: 0.61 MB.
~~~~
If we enable the garbage collector and remove the dispose() method, the
used memory level begins to increase, and if we call gc_collect_cycles()
after creating a new object, the used memory increases even much faster.
On my PC, it is not able to perform display even a single control
message after 100000 iterations. It stopped after approx. 33000 users:
~~~~
memory usage after 30,000 users: 25.37 MB.
memory usage after 31,000 users: 26.07 MB.
memory usage after 32,000 users: 26.76 MB.
memory usage after 33,000 users: 31.46 MB.
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to
allocate 89 bytes) in /home/me/test/memleak.php on line 17
~~~~
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
http://bugs.php.net/bug.php?id=48781
--
Edit this bug report at http://bugs.php.net/bug.php?id=48781&edit=1