On 25/09/06, Jon Anderson <[EMAIL PROTECTED]> wrote:
I posted this to php-general several days ago, and the only response
suggested that perhaps I should forward the question to PHP internals.
If what's below isn't expected behavior, I'd be glad to dedicate a few
days to helping track down the problem.
I've tried what's below on the server cluster in the office, running
Debian Sarge i386 (with an x86-64 kernel), PHP 5.0.16, and Apache
2.0.54. I've also tried at home on a Gentoo box (Athlon-MPs) running PHP
5.0.16 and Apache 2.2. Both produce similar results. (If
compiled-in/shared module lists, compile options, or any other
information would help, I can provide those too.)
What's below this sentence is the original text of the message sent to
php-general.
Sorry folks, this is a long one...I've re-read a bunch of the
documentation, and I can't find a solution.
In debugging an out of memory condition, I found that PHP doesn't seem
to garbage collect unreferenced objects. It seems to work fine for
anything other than objects. (Arrays, strings, integers, etc.)
Here's a simple example: define a class, create 3 instances, destroy
them in reverse order. I would expect that after each unset and/or NULL,
the memory usage would go down, they don't. See the output below.
<?php
class Tester {
protected $test1;
protected $test2;
protected $test3;
protected $test4;
public function __construct() {
$test1 = rand();
$test2 = rand();
$test3 = rand();
$test4 = rand();
}
}
echo memory_get_usage() . "\n";
$t1 = new Tester();
echo memory_get_usage() . "\n";
$t2 = new Tester();
echo memory_get_usage() . "\n";
$t3 = new Tester();
echo memory_get_usage() . "\n";
unset($t3);
$t3 = NULL;
echo memory_get_usage() . "\n";
$t2 = NULL;
echo memory_get_usage() . "\n";
unset($t1);
echo memory_get_usage() . "\n";
This outputs:
43344
43928
44232
44568
44640
44640
44640
Note: the memory usage remains constant after the objects are allocated,
even when they're unset/NULL'ed.
Some of the user contributed notes on the PHP documentation suggest that
the memory is actually freed and available for use by other
variables/objects even though memory_get_usage() says otherwise. Another
little test seems to disprove that too... The idea here is to allocate
close to 8 MB, then free it to show that it can allocate that data
within the memory limit. Then allocate enough class instances and free
them again such that the memory usage increases enough that the same
data allocated and freed initially doesn't fit anymore. If PHP did
indeed free the objects, the data would fit the second time too...
<?php
ini_set('memory_limit','8m');
class Tester {
protected $test;
public function __construct() {
$this->test = rand();
}
}
echo "Initial Memory Usage: " . memory_get_usage() . "\n";
$mb = 6 * 1024 * 1024;
echo "Allocating 7 MB of data...";
$dat = "";
for ($x=0;$x<$mb;$x++) {
$dat .= "x";
}
echo "Memory Usage: " . memory_get_usage() . "\n";
unset($dat,$x,$mb);
echo "Unset Usage: " . memory_get_usage() . "\n";
$num = 32767;
$objects = array();
echo "Initial Memory Usage (2): " . memory_get_usage() . "\n";
echo "Allocating $num objects...";
for ($x=0;$x<$num;$x++) {
$objects[$x] = new Tester();
}
echo "Done. Memory Usage: " . memory_get_usage() . "\n";
echo "Freeing $num objects...";
for ($x=0;$x<$num;$x++) {
unset($objects[$x]); $objects[$x] = NULL;
}
echo "Done. Memory Usage: " . memory_get_usage() . "\n";
$mb = 6 * 1024 * 1024;
echo "Allocating 7 MB of data...";
$dat = "";
for ($x=0;$x<$mb;$x++) {
$dat .= "x";
}
This gives:
Initial Memory Usage: 44248
Allocating 7 MB of data...Memory Usage: 6335888
Unset Usage: 44448
Initial Memory Usage (2): 44504
Allocating 32767 objects...Done. Memory Usage: 7752920
Freeing 32767 objects...Done. Memory Usage: 2807080
Allocating 7 MB of data...
Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to
allocate 1 bytes) in /home/janderson/svn/memtest.php on line 44
Am I missing something? (Is there a force_garbage_collection() function
somewhere that I'm missing?) Any suggestions/workarounds/anything would
be most appreciated.
Cheers,
jon
Using PHP 5.2.0RC5-dev (cli) (built: Sep 18 2006 08:20:52) on Windows
(which has no memory_get_usage() functions), the scripts work fine.
Allocating 7 MB of data...Allocating 32767 objects...Freeing 32767
objects...Allocating 7 MB of data...
Using System Internals Process Explorer, you can see the memory
increase and decrease as expected.
Using the same script via ISAPI also worked as expected.
Not much help in answering the issue, so maybe this is an issue that
has been fixed already?
--
-----
Richard Quadling
Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
"Standing on the shoulders of some very clever giants!"
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php