I've written a PHP CLI app that runs on our server constantly. The application will slowly build up memory until it reaches the memory_limit and then crash. I've tried using unset on my objects once they are no longer needed, but that doesn't seem to free up the memory they've used. Does anyone know a good method for recovering that memory my objects used to use? Any advice is greatly appreciated. As an example I've got some basic code that builds up a good chunk of memory and doesn't release it like it should:
#!/usr/local/bin/php -c /usr/local/etc/php-cli.ini
<?PHP
class TestObj{
private $testArr;
public function __construct(){}
public function __destruct(){
unset($testArr);
}
public function testme(){
$this->testArr = array();
for($i = 0; $i < 100000; $i++){
$something = "";
for($j = 0; $j < 10; $j++){
$something .= chr(rand(35,126) );
}
$this->testArr[$i] = $something;
}
/*
foreach($this->testArr as $ta){
echo $ta,"\n";
}
*/
}
}
$loop = true;
echo "Initial Memory Usage: ".memory_get_usage()."\n\n";
sleep(10);
echo "Creating New Object\n\n";
$test = new TestObj();
echo "Running Test Function\n\n";
$test->testme();
echo "Ready to destroy object in...";
for($x=5 ; $x > 0; $x--){
sleep(1);
echo $x, "...";
}
unset($test);
echo "\nSleepy Time\n";
sleep(30);
?>What sort of system is this? I've tried it on both machines I have to hand - one Windows and one Un*x - with two different versions of PHP, and they worked as expected.
I don't see anything in the PHP5 changelog (at a quick glance), but there may be something in the bugtracker.The garbage collection in PHP is sometimes less than desirable.
For a constantly running script, I think you'll be better off to create and run it as a daemon. This will probably require having the Process Control Functions (<!-- m --><a class="postlink" href="http://www.php.net/manual/en/ref.pcntl.php">http://www.php.net/manual/en/ref.pcntl.php</a><!-- m -->) installed though. And possibly also require PHP compiled with "--enable-sigchild" too.
Since the normal way daemons work is to "fork off and die", that should eliminate memory problems that might arise from a PHP script running for a long time.
There is at least one decent PHP daemon script over at phpclasses.orgI believe that the PHP GC works using reference counting (or at least, it used to). This means that circularly referenced objects may not be released until the end of the script.
You will not generally see freed memory be removed from the process's working set in "ps" or "top", but that should not be a problem (it's still freed internally).
PHP does appear to clean up objects as soon as they have no live references - but I'm not sure what its behaviour is for circularly referenced objects.
You can try to avoid circular references or have a special method on your object which unhooks references which could be circular.
There may be some built-in objects in PHP which utilise circular references (e.g. DOM?) - in which case you won't be able to do a lot about them.
The above script does not appear to be long-lived - it exits after 30 seconds. Is this what you had intended?
How did you determine that the above code "doesn't release the memory like it should"?
Mark
#!/usr/local/bin/php -c /usr/local/etc/php-cli.ini
<?PHP
class TestObj{
private $testArr;
public function __construct(){}
public function __destruct(){
unset($testArr);
}
public function testme(){
$this->testArr = array();
for($i = 0; $i < 100000; $i++){
$something = "";
for($j = 0; $j < 10; $j++){
$something .= chr(rand(35,126) );
}
$this->testArr[$i] = $something;
}
/*
foreach($this->testArr as $ta){
echo $ta,"\n";
}
*/
}
}
$loop = true;
echo "Initial Memory Usage: ".memory_get_usage()."\n\n";
sleep(10);
echo "Creating New Object\n\n";
$test = new TestObj();
echo "Running Test Function\n\n";
$test->testme();
echo "Ready to destroy object in...";
for($x=5 ; $x > 0; $x--){
sleep(1);
echo $x, "...";
}
unset($test);
echo "\nSleepy Time\n";
sleep(30);
?>What sort of system is this? I've tried it on both machines I have to hand - one Windows and one Un*x - with two different versions of PHP, and they worked as expected.
I don't see anything in the PHP5 changelog (at a quick glance), but there may be something in the bugtracker.The garbage collection in PHP is sometimes less than desirable.
For a constantly running script, I think you'll be better off to create and run it as a daemon. This will probably require having the Process Control Functions (<!-- m --><a class="postlink" href="http://www.php.net/manual/en/ref.pcntl.php">http://www.php.net/manual/en/ref.pcntl.php</a><!-- m -->) installed though. And possibly also require PHP compiled with "--enable-sigchild" too.
Since the normal way daemons work is to "fork off and die", that should eliminate memory problems that might arise from a PHP script running for a long time.
There is at least one decent PHP daemon script over at phpclasses.orgI believe that the PHP GC works using reference counting (or at least, it used to). This means that circularly referenced objects may not be released until the end of the script.
You will not generally see freed memory be removed from the process's working set in "ps" or "top", but that should not be a problem (it's still freed internally).
PHP does appear to clean up objects as soon as they have no live references - but I'm not sure what its behaviour is for circularly referenced objects.
You can try to avoid circular references or have a special method on your object which unhooks references which could be circular.
There may be some built-in objects in PHP which utilise circular references (e.g. DOM?) - in which case you won't be able to do a lot about them.
The above script does not appear to be long-lived - it exits after 30 seconds. Is this what you had intended?
How did you determine that the above code "doesn't release the memory like it should"?
Mark