What's better at freeing memory with PHP: unset() or $var = null
I realise the second one avoids the overhead of a function call (update, is actually a language construct), but it would be interesting to know if one is better than the other. I have been using unset()
for most of my coding, but I've recently looked through a few respectable classes found off the net that use $var = null
instead.
Is there a preferred one, and what is the reasoning?
Solution 1:
It was mentioned in the unset manual's page in 2009:
unset()
does just what its name says - unset a variable. It does not force immediate memory freeing. PHP's garbage collector will do it when it see fits - by intention as soon, as those CPU cycles aren't needed anyway, or as late as before the script would run out of memory, whatever occurs first.If you are doing
$whatever = null;
then you are rewriting variable's data. You might get memory freed / shrunk faster, but it may steal CPU cycles from the code that truly needs them sooner, resulting in a longer overall execution time.
(Since 2013, that unset
man page don't include that section anymore)
Note that until php5.3, if you have two objects in circular reference, such as in a parent-child relationship, calling unset() on the parent object will not free the memory used for the parent reference in the child object. (Nor will the memory be freed when the parent object is garbage-collected.) (bug 33595)
The question "difference between unset and = null" details some differences:
unset($a)
also removes $a
from the symbol table; for example:
$a = str_repeat('hello world ', 100);
unset($a);
var_dump($a);
Outputs:
Notice: Undefined variable: a in xxx
NULL
But when
$a = null
is used:
$a = str_repeat('hello world ', 100);
$a = null;
var_dump($a);
Outputs:
NULL
It seems that
$a = null
is a bit faster than itsunset()
counterpart: updating a symbol table entry appears to be faster than removing it.
- when you try to use a non-existent (
unset
) variable, an error will be triggered and the value for the variable expression will be null. (Because, what else should PHP do? Every expression needs to result in some value.) - A variable with null assigned to it is still a perfectly normal variable though.
Solution 2:
unset
is not actually a function, but a language construct. It is no more a function call than a return
or an include
.
Aside from performance issues, using unset
makes your code's intent much clearer.
Solution 3:
By doing an unset() on a variable, you've essentially marked the variable for 'garbage collection' (PHP doesn't really have one, but for example's sake) so the memory isn't immediately available. The variable no longer houses the data, but the stack remains at the larger size. Doing the null method drops the data and shrinks the stack memory almost immediately.
This has been from personal experience and others as well. See the comments of the unset() function here.
I personally use unset() between iterations in a loop so that I don't have to have the delay of the stack being yo-yo'd in size. The data is gone, but the footprint remains. On the next iteration, the memory is already being taken by php and thus, quicker to initialize the next variable.
Solution 4:
<?php
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
$a = NULL;
}
$elapsed = microtime(true) - $start;
echo "took $elapsed seconds\r\n";
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
unset($a);
}
$elapsed = microtime(true) - $start;
echo "took $elapsed seconds\r\n";
?>
Per that it seems like "= null" is faster.
PHP 5.4 results:
- took 0.88389301300049 seconds
- took 2.1757180690765 seconds
PHP 5.3 results:
- took 1.7235369682312 seconds
- took 2.9490959644318 seconds
PHP 5.2 results:
- took 3.0069220066071 seconds
- took 4.7002630233765 seconds
PHP 5.1 results:
- took 2.6272349357605 seconds
- took 5.0403649806976 seconds
Things start to look different with PHP 5.0 and 4.4.
5.0:
- took 10.038941144943 seconds
- took 7.0874409675598 seconds
4.4:
- took 7.5352551937103 seconds
- took 6.6245851516724 seconds
Keep in mind microtime(true) doesn't work in PHP 4.4 so I had to use the microtime_float example given in php.net/microtime / Example #1.
Solution 5:
It works in a different way for variables copied by reference:
$a = 5;
$b = &$a;
unset($b); // just say $b should not point to any variable
print $a; // 5
$a = 5;
$b = &$a;
$b = null; // rewrites value of $b (and $a)
print $a; // nothing, because $a = null