Помогает ли ссылаться на переменную в 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;
}
Ответы
Ответ 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);