PHP - What's the Benefit of Unsetting Variables

php - what's the benefit of unsetting variables?

Is it true that unsetting variables
doesn't actually decrease the memory
consumption during runtime?

Yep. From PHP.net:

unset() does just what it's 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.

Regarding your other question:

And is there any reason to unset
variables apart from destroying
session varaibles for instance or for
scoping?

Not really, you pretty much summed it.

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

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.

How important is it to unset variables in PHP?

See this example (and the article I linked below the question):

$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n"; // 120172
echo memory_get_peak_usage() . "<br>\n"; // 121248

$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n"; // 120172
echo memory_get_peak_usage() . "<br>\n"; // 201284

As you can see, at one point PHP had used up almost double the memory. This is because before assigning the 'x'-string to $x, PHP builds the new string in memory, while holding the previous variable in memory, too. This could have been prevented with unsetting $x.

Another example:

for ($i=0; $i<3; $i++) {
$str = str_repeat("Hello", 10000);
echo memory_get_peak_usage(), PHP_EOL;
}

This will output something like

375696
425824
425824

At the first iteration $str is still empty before assignment. On the second iteration $str will hold the generated string though. When str_repeat is then called for the second time, it will not immediately overwrite $str, but first create the string that is to be assigned in memory. So you end up with $str and the value it should be assigned. Double memory. If you unset $str, this will not happen:

for($i=0;$i<3;$i++) {
$str = str_repeat("Hello", 10000);
echo memory_get_peak_usage(), PHP_EOL;
unset($str);
}

// outputs something like
375904
376016
376016

Does it matter? Well, the linked article sums it quite good with

This isn't critical, except when it is.

It doesn't hurt to unset your variables when you no longer need them. Maybe you are on a shared host and want to do some iterating over large datasets. If unsetting would prevent PHP from ending with Allowed memory size of XXXX bytes exhausted, then it's worth the tiny effort.

What should also be taken into account is, that even if the request lifetime is just a second, doubling the memory usage effectively halves the maximum amount of simultaneous requests that can be served. If you are nowhere close to the server's limit anyway, then who cares, but if you are, then a simple unset could save you the money for more RAM or an additional server.

Should I unset my PHP array values?

It is a good idea to start unsetting variables if you know they use a lot of memory, like huge images, or big SQL query results, but only if you know for sure the info isn't needed anymore, and if your PHP complains about not having enough memory. Or your webserver. Freeing tiny parts of memory in the middle of a block of still used memory is useless. It won't be reused. And reordering the memory would eat performance. PHP is pretty optimized in dealing with variables.

Unsetting a variable will free it's memory if there is no other reference pointing to the value. This is true for an array as well: All array keys are references to their values, and if they are the only one, unsetting the array itself will unset all stored values inside.

You should know that query results are stored entirely in memory. You cannot access it directly, but there are functions like mysqli_result::data_seek() that will let you point to the entry you want to read, and the next call to mysqli_result::fetch_assoc() will get it.

If you are really copying the result to an array, you are at least doubling your memory consumption until you delete the query result (either explicitly with a call to mysqli_result::free(), or by unsetting the result object).

You could however also create a wrapper around the mysqli_result that implements the ArrayAccess interface (and probably also Iterator and Countable). This IS your array - without copying. An access to a random value would first call seek(), then fetch_assoc(), and return the value.

You then have the freedom to make use of all the SPL classes. Want to filter the result when running over it with foreach? Implement your own FilterIterator, put your result wrapper inside, and there you go.

Is unset useful?

It depends.

If you're developing a long-running daemon or job, unset() can be used to keep memory in reasonable bounds: to help prevent leaks.

If you're developing a page/script for a web application, unset() isn't terribly useful for memory management.

And in either case, it's useful if you're relying on arrays and you need to remove a value. A silly example, perhaps ... but consider something like this:

$users = getUsers($someCondition);
foreach ($users as $k => $v) {
unset($users[$k]['password_hash']);
}
print json_encode($users);

In the specific example you've given, it's useless:

<?php
$message = "Line 1\r\nLine 2\r\nLine 3";
mail('admin@example.com', 'My Subject', $message);

// PHP is about to clean everything up anyway ... don't bother doing this:
unset($message);
?>

When unset() should really be used?

In php, all memory gets cleaned up after script is finished, and most of the time it's enough.

From php.net:

unset() does just what it's 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.

In reality you would use unset() for cleaning memory pretty rare, and it's described good in this post:
https://stackoverflow.com/a/2617786/1870446

By doing an unset() on a variable, you mark the variable for being "garbage collected" so the memory isn't immediately available. The variable does not have the data anymore, but the stack remains at the larger size.

In PHP >= 5.3.0, you can call gc_collect_cycles() to force a GC pass. (after doing gc_enable() first).

But you must understand that PHP is script language, it's not Java so you shouldn't consider it like one. If your script is really that heavy to use tons of RAM - you can use unset and when script is close to exceed the memory - GC will trigger and clean up everything useless, including your unset variables. But in most cases you can forget about it.

Also, if you would want to go for unsetting every variable you do not use - don't. It will actually make your script execute longer - by using more CPU cycles - for the sake of getting free memory that would, in most cases, would never be needed.

Some people also say that they use unset to explicitly show that they won't use variable anymore. I find it a bad practice too, for me it just makes code more verbose with all these useless unsets.

Do we need to “unset” variables in JavaScript?

No, plus in some cases you can't delete variables in the global scope. Variables that are properly declared using the var keyword cannot be deleted (implied global variables can be deleted, on the other hand. Always use the var keyword to declare variables).

Also, javascript engines have this thing called garbage collector that automatically looks for variables that are no longer used or referenced somewhere when your code is 'running'. Once it finds one, it'll shove it off immediately into the Abyss (deletes the variable in the memory)

Unsetting a variable vs setting to ''

they will do slightly different things:

  • unset will remove the variable from the symbol table and will decrement the reference count on the contents by 1. references to the variable after that will trigger a notice ("undefined variable"). (note, an object can override the default unset behavior on its properties by implementing __unset()).

  • setting to an empty string will decrement the reference count on the contents by 1, set the contents to a 0-length string, but the symbol will still remain in the symbol table, and you can still reference the variable. (note, an object can override the default assignment behavior on its properties by implementing __set()).

in older php's, when the ref count falls to 0, the destructor is called and the memory is freed immediately. in newer versions (>= 5.3), php uses a buffered scheme that has better handling for cyclical references (http://www.php.net/manual/en/features.gc.collecting-cycles.php), so the memory could possibly be freed later, tho it might not be delayed at all... in any case, that doesn't really cause any issues and the new algorithm prevents certain memory leaks.

if the variable name won't be used again, unset should be a few cpu cycles faster (since new contents don't need to be created). but if the variable name is re-used, php would have to create a new variable and symbol table entry, so it could be slower! the diff would be a negligible difference in most situations.

if you want to mark the variable as invalid for later checking, you could set it to false or null. that would be better than testing with isset() because a typo in the variable name would return false without any error... you can also pass false and null values to another function and retain the sentinel value, which can't be done with an unset var...

so i would say:

$var = false; ...
if ($var !== false) ...

or

$var = null; ...
if (!is_null($var)) ...

would be better for checking sentinel values than

unset($var); ...
if (isset($var)) ...

php function to unset variables passed by reference

According to the manual for unset:

If a variable that is PASSED BY REFERENCE is unset() inside of a
function, only the local variable is destroyed. The variable in the
calling environment will retain the same value as before unset() was
called.

I assume this is the issue you're encountering. So, my suggestion is to simply set $argument to NULL. Which, according to the NULL docs will "remove the variable and unset its value.".

For example:
$argument = NULL;

Unsetting local variables

unset() destroys the specified variables. but unset() does not free the memory consumed by the PHP script, it does free it for use by the PHP script itself. 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.

So, if you are creating a variable of 10M of size 10 times in a loop and unsetting (or rewriting) it at the end of the loop, the memory consumption should be as low as 10M + all other variables by the end of the loop.

Read more

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

why UNSET and NULL are working in different ways



Related Topics



Leave a reply



Submit