Подтвердить что ты не робот

Помогает ли ссылаться на переменную в php-функции на сохранение памяти?

Например, следующие две функции одинаковы или нет, когда сравниваются способы управления памятью:

$hello = 'hello';

my_echo($hello);

//Better or worse than
my_echo_ref($hello);

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

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

Ответ 1

Я не знаю, насколько достоверен этот источник, но это очень интересная статья (с 2008 года), в которой объясняется, как обрабатываются переменные:

Правда о переменных PHP

В нем говорится

Я хотел написать это сообщение, чтобы выяснить, что похоже на распространенное недоразумение в PHP, - что использование ссылок при передаче вокруг больших переменных - хороший способ сохранить память.

и

(...) Хотя приведенное выше объяснение ссылок достаточно для общего понимания, часто полезно понять, как PHP обрабатывает назначение переменных внутри. Здесь мы вводим понятие zval.

zvals - это внутренняя структура PHP, которая используется для хранения переменных. Каждый zval содержит различные фрагменты информации, и те, на которые мы будем фокусироваться, следующие:

  • Фактические данные, хранящиеся в zval. В нашем примере это будет либо "привет! или" до свидания!"
  • is_ref Булевский флаг
  • Счетчик ref_count

(...)

и

(...) Когда вы назначаете переменную по значению (например, в примере 1), она не создает новый zval, она просто указывает обе переменные на один и тот же zval и увеличивает значение zvals ref_count на единицу. "Подождите!" Я слышу, как ты плачешь: "Разве это не мимоходом?" Ну, хотя это звучит так же, все PHP делает, откладывает любое копирование, пока оно действительно не будет, и это знает об этом, потому что is_ref по-прежнему является ложным. (...)

и заключение:

Вы можете видеть, что, если разработчик полностью несовместим, передача переменных с помощью reference может легко привести к использованию увеличенной памяти.


Кроме того, я несколько раз запускал ваш код с get_memory_usage() и не было разницы в потреблении памяти (но это не обязательно означает ничего, возможно, потребление памяти отличается тем, что на самом деле что-то делает с переменной).

Ответ 2

Для записи (php 7.0 - win32)

Я тестирую его (я передал переменную функции, а затем изменил значение внутри функции), и я нашел:

a) unset ($ var) и $var = null действуют одинаково.

b) передача массива по ссылке в зависимости от значения, удваивает использование памяти в какой-то момент. Почему?, я не знаю. Я нашел его с memory_get_peak_usage(). Однако memory_get_usage() не изменится, поэтому я предполагаю, что он дублирует информацию (может быть во временной переменной), затем она отбрасывается.

Например: (память просто приближается)

  $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. !!! 
  }

но

  $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. !!! 
  }

и

  $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???
  }

и

  $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) передача параметров в качестве значения или ссылки практически не изменит время выполнения.

d) передача объектов в качестве ссылки удваивает использование памяти в какой-то момент.

Ответ 3

Передача по ссылке - хороший способ не увеличивать память, если переменная, переданная, будет изменена внутри функции.

В моих тестах (PHP 5.5.9) передача по ссылке или по рекурсивному значению не имеет существенной разницы , только если вы не измените переданную переменную $.

Каждый раз, когда функция изменяет переменную и передает ее другой функции по значению, происходит дублирование в памяти.

Вот результаты моего теста.

введите описание изображения здесь

И ниже приведен код PHP, если вы хотите попробовать:

    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);