As I’m coding with PHP since years now, I’m used to the language. I’m doing now some website in PHP with part of their processing into CLI php scripts, which are sometimes manipulating high amount of data.. This was the case with one of my scripts, which was loading 28.000 object from a database, to treat them one by one.
After the load of the object, I was using a foreach to loop through the array and at the end of each iteration, I was actually unsetting the current object and removing it from the array, to allow memory to be freed after each object was treated. Unfortunately, it didn’t worked. I was running out of memory very quickly.
I’ve then found the issue, by using a little test script like this:
<?php class Test { public $id = 0; public $var1 = ""; public function __construct($id) { $this->id = $id; } } $myarray = array(); for($i=0;$i<25000;$i++) { $v = new Test($i); $myarray = $v; } $mu = memory_get_usage(); echo "- Memory usage: ".number_format($mu) . "\n"; foreach($myarray as $k => $v) { $v->var1 = "mystring1"; unset($v); unset($myarray$k); $m = memory_get_usage(); $diff = $mu - $m; echo "- Difference: ".number_format($diff)."\n"; } ?>
As you could see if you run this little script in CLI, php memory usage’s growing after each iteration, despite the unsets. The problem comes from the “foreach”, which seems to cache the array before iterating, this hold references to the object that aren’t getting freed. To fix the issue, replace the loop with the following code;
for($i=0,$c=count($myarray);$i<$c;$i++) { $v = $myarray$i; $v->var1 = "mystring1"; unset($v); unset($myarray$i); $m = memory_get_usage(); $diff = $mu - $m; echo "- Difference: ".number_format($diff)."\n"; }
And there it is, now php free correctly the objects after each iteration.