What's better at freeing memory with PHP: unset() or $var = null

Viewed 211986

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?

13 Answers

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 its unset() 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.

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.

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.

PHP 7 is already worked on such memory management issues and its reduced up-to minimal usage.

<?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";

?>

PHP 7.1 Outpu:

took 0.16778993606567 seconds took 0.16630101203918 seconds

Code example from comment

echo "PHP Version: " . phpversion() . PHP_EOL . PHP_EOL;

$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    $a = NULL;
}
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds" . PHP_EOL;



$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    unset($a);
}
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds" . PHP_EOL;

Running in docker container from image php:7.4-fpm and others..

PHP Version: 7.4.8
took 0.22569918632507 seconds null
took 0.11705803871155 seconds unset
took 0.20791196823121 seconds null
took 0.11697316169739 seconds unset

PHP Version: 7.3.20
took 0.22086310386658 seconds null
took 0.11882591247559 seconds unset
took 0.21383500099182 seconds null
took 0.11916995048523 seconds unset

PHP Version: 7.2.32
took 0.24728178977966 seconds null
took 0.12719893455505 seconds unset
took 0.23839902877808 seconds null
took 0.12744522094727 seconds unset

PHP Version: 7.1.33
took 0.51380109786987 seconds null
took 0.50135898590088 seconds unset
took 0.50358104705811 seconds null
took 0.50115609169006 seconds unset

PHP Version: 7.0.33
took 0.50918698310852 seconds null
took 0.50490307807922 seconds unset
took 0.50227618217468 seconds null
took 0.50514912605286 seconds unset

PHP Version: 5.6.40
took 1.0063569545746 seconds null
took 1.6303179264069 seconds unset
took 1.0689589977264 seconds null
took 1.6382601261139 seconds unset

PHP Version: 5.4.45
took 1.0791940689087 seconds null
took 1.6308979988098 seconds unset
took 1.0029168128967 seconds null
took 1.6320278644562 seconds unset

But, with other example:

<?php
ini_set("memory_limit", "512M");

echo "PHP Version: " . phpversion() . PHP_EOL . PHP_EOL;

$start = microtime(true);
$arr = [];
for ($i = 0; $i < 1000000; $i++) {
    $arr[] = 'a';
}
$arr = null;
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds" . PHP_EOL;



$start = microtime(true);
$arr = [];
for ($i = 0; $i < 1000000; $i++) {
    $arr[] = 'a';
}
unset($arr);
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds" . PHP_EOL;

Results:

PHP Version: 7.4.8
took 0.053696155548096 seconds
took 0.053897857666016 seconds

PHP Version: 7.3.20
took 0.054572820663452 seconds
took 0.054342031478882 seconds

PHP Version: 7.2.32
took 0.05678391456604 seconds
took 0.057311058044434 seconds


PHP Version: 7.1.33
took 0.097366094589233 seconds
took 0.073100090026855 seconds

PHP Version: 7.0.33
took 0.076443910598755 seconds
took 0.077098846435547 seconds

PHP Version: 7.0.33
took 0.075634002685547 seconds
took 0.075317859649658 seconds

PHP Version: 5.6.40
took 0.29681086540222 seconds
took 0.28199100494385 seconds

PHP Version: 5.4.45
took 0.30513095855713 seconds
took 0.29265689849854 seconds

Related