Возвращать большие данные по ссылке или как возврат в функцию?

На сегодняшней работе я столкнулся с коллажем о передаче больших данных между областями. Миф заключался в том, что ссылка использует меньше использования памяти/ЦП при передаче между двумя областями. Мы строим доказательство концепции, которая была права... так:

function by_return($dummy=null) {
    $dummy = str_repeat("1",100 * 1024 * 1024);
    return $dummy;
}

function by_reference(&$dummy) {
    $dummy = null;
    $dummy = str_repeat("1",100 * 1024 * 1024);
}
echo memory_get_usage()."/".memory_get_peak_usage()."\n";
//1 always returns: 105493696/105496656
$nagid = by_return();
echo memory_get_usage()."/".memory_get_peak_usage()."\n";
unset($nagid);
//2 always returns:  105493696/210354184 even if we comment 1st part
by_reference($dummy);
echo memory_get_usage()."/".memory_get_peak_usage()."\n";
unset($dummy);

Но похоже, что по ссылке он потребляет больше памяти в соответствии с функцией "memory_get_peak_usage()"

Как вы видите, использование больших данных для возврата намного умнее, чем использование в качестве ссылки, но вопрос в том, почему? Любое просвещение приветствуется:)

Ответ 1

Это связано с тем, как php обрабатывает переменные и немного интуитивно понятен любому, кто работал на C или С++.

Передача по ссылке более умная, чем PHP, не рекомендуется. PHP на самом деле не делает копии данных, если это необходимо (например, вы изменяете значение переменной при наличии более 1 ссылки на него), стратегия оптимизации очень похожа на копию на запись для страниц общей памяти.

Итак, скажем, у вас есть переменная, которую вы передаете по значению несколько раз в заданном script. Если вы затем берете эту переменную и передаете ее по ссылке, вы фактически дублируете переменную, а не просто получаете указатель на объект.

Это происходит из-за того, что внутренне PHP zvals (структура данных, используемая PHP для хранения переменных) могут быть только ссылочными переменными или переменными без ссылки. Поэтому не имеет значения, что такое поле zval ref_count, потому что это не ссылочная переменная (поле is_ref структуры zval). Поэтому внутренне PHP вынужден создать новый zval и установить его поле is_ref в true, тем самым удваивая память.

Сообщите своему коллеге прекратить попытки перехитрить PHP. Передача по ссылке, если не сделана на 100% отлично во всем коде, вызовет много накладных расходов и удвоит использование памяти.

Более подробное обсуждение см. по этой ссылке: http://porteightyeight.com/2008/03/18/the-truth-about-php-variables/