开发者

Does referencing a variable in a php function help save memory?

开发者 https://www.devze.com 2023-01-04 17:04 出处:网络
For example are the following two functions the same or not when one compares how memory is being managed:

For example are the following two functions the same or not when one compares how memory is being managed:

$hello = 'hello';

my_echo($hello);

//Better or worse than
my_echo_开发者_如何学Cref($hello);

//case 1, no referencing:
function my_echo($word) {
 echo $word;
} 

//case 2, referencing:
function my_echo_ref(&$word) {
  echo $word;
}


I don't know how reliable this source is, but this is a very interesting article (from 2008) that explains how variables are handled:

The Truth About PHP Variables

It says

I wanted to write this post to clear up what seems to be a common misunderstanding in PHP – that using references when passing around large variables is a good way save memory.

and

(...) While the above explanation of references is sufficient for a general understanding, it is often useful to understand how PHP handles variable assignment internally. This is where we introduce the concept of the zval.

zvals are an internal PHP structure which are used for storing variables. Each zval contains various pieces of information, and the ones we will be focusing on here are as follows:

  • The actual data stored within the zval – In our example this would be either ‘hello!’ or ‘goodbye!’
  • is_ref Boolean flag
  • A ref_count counter

(...)

and

(...) When you assign a variable by value (such as in example 1) it does not create a new zval, it simply points both variables at the same zval and increases that zval’s ref_count by one. “Wait!” I hear you cry, “Isn’t that passing by reference?” Well, although it sounds the same, all PHP is doing is postponing any copying until it really has to – and it knows this because is_ref is still false. (...)

and the conclusion:

You can see that, unless the developer is completely consistent, passing variables by reference can easily lead to increased memory usage.


Besides that, I ran your code a few times with get_memory_usage() and there was no difference in memory consumption (but this does not necessarily mean anything, probably the memory consumption differs when one is actually doing something with the variable).


For the record (php 7.0 - win32)

I am testing it (i passed a variable to a function then i changed the value inside the function) and i found:

a) unset($var) and $var=null act equally.

b) passing an array by reference versus by value, doubles the memory usage at some point. Why?, i don't know. I found it with memory_get_peak_usage(). However, memory_get_usage() will not change so i guess that its duplicates the information (may be in a temporal variable) then it discards.

For example: (the memory is just an approximation)

  $var= (10mb of data as an array)  = memory peak 10mb.
  function functionval($var) {
       $var= (100mb of data) = memory peak 110mb.
  }
  function functionref(&$var) {
       $var= (100mb of data) = memory peak 210mb. !!! 
  }

but

  $var= (100mb of data as an array)  = memory peak 100mb.
  function functionval($var) {
       $var= (10mb of data) = memory peak 110mb.
  }
  function functionref(&$var) {
       $var= (10mb of data) = memory peak 120mb. !!! 
  }

and

  $var= (100mb of data as an array)  = memory peak 100mb.
  function functionval($var) {
       $var= (100mb of data) = memory peak 200mb.
  }
  function functionref(&$var) {
       $var= (100mb of data) = memory peak 300mb. !!! <-- why???
  }

also

  $var= (100mb of data as an array)  = memory peak 100mb.
  function functionval($var) {
       not changing the data. = memory peak 100mb.
  }
  function functionref(&$var) {
       not changing the data. = memory peak 100mb.
  }

c) passing parameters as value or reference will practically not change the execution time.

d) passing objects as reference, doubles the memory usage at some point.


Passing by reference is a good way to not increase memory if the variable passed is going to be modified inside the function.

In my tests (PHP 5.5.9) passing by reference or by value recursively does not any significant difference only if you do not change the passed $variable.

Everytime the function modifies the variable and pass it to another function by value a duplication in memory occurs.

Here are the results of my test.

Does referencing a variable in a php function help save memory?

And below is the PHP code if you want to try:

    global $m1, $recursion_level;

    $variable = []; // array with dummy data
    $data = str_pad('*', 256); // Dummy data
    $recursion_level = 5; // recursion levels of by_val and by_ref functions

    $m1 = memory_get_usage(); // measuring actual memory usage before setting/filling $variable

    for ($i = 1; $i < 1000; $i++) {
        $variable[] = $data;
    }

    print 'APROX size of $variable: ' . ( memory_get_usage() - $m1 ) . '<br/>';

    // recursive function passing $variable by reference
    function by_ref(&$ref, $level) {
        global $m1, $recursion_level;

        $ref[0] = ''; // Changing one element does the difference...

        print 'LEVEL ' . ($recursion_level - $level) . ': ' . (memory_get_usage() - $m1) . '<br/>';

        if ($level-- > 0) {
            by_ref($ref, $level);
        }
    }

    // recursive function passing $variable by value
    function by_val($val, $level) {
        global $m1, $recursion_level;

        print 'LEVEL ' . ($recursion_level - $level) . ': ' . (memory_get_usage() - $m1) . '<br/>';

        $val[0] = ''; // Changing one element does the difference...

        if ($level-- > 0) {
            by_val($val, $level);
        }
    }

    print '<br/><br/>MEMORY SIZE PASSING BY VAL<hr/>';
    by_val($variable, $recursion_level);

    print '<br/><br/>MEMORY SIZE PASSING BY REF<hr/>';
    by_ref($variable, $recursion_level);


By reference is better if you are using the array as a source of data, to build a second array, and you simplify the array dimensions by assigning a variable to it...

example:

$clients_favorite_things=array_fill(0,20,array("movies"=>array("movie 1","movie 2","movie 3"),"books"=>array("book 1","book 2","book 3") ));
$clients = array_fill(0,20,array());

//Goal is to have a final clients array with only movies data assuming the index of this array is the client id

$m1 = memory_get_usage(); 
foreach($clients as $client_id => $client_data){
    $favorite_things=$clients_favorite_things[$client_id]; //this does copy data
    $clients[$client_id]["favorite_things"]=$favorite_things["movies"];
}
print 'APROX size ' . ( memory_get_usage() - $m1 ) . '<br/>';

$m1 = memory_get_usage(); 
foreach($clients as $client_id => $client_data){
    $favorite_things=&$clients_favorite_things[$client_id]; //assign by reference: this wont copy data
    $clients[$client_id]["favorite_things"]=$favorite_things["movies"];
}
print 'APROX size ' . ( memory_get_usage() - $m1 ) . '<br/>';

print_r($clients); 

APROX size : 7520
APROX size : 856

0

精彩评论

暂无评论...
验证码 换一张
取 消