2

Предположим, что у меня есть две переменные и они равны null. (Более реалистично, я думаю о массиве, который содержит большое количество null s, но сценария «двух переменных» достаточно для вопроса.) Очевидно, что я могу сделать это более чем одним способом. Я могу сделать это (метод 1):PHP null и copy-on-write

$a = null; 
$b = $a; 

По моему разумению, результатом этого является то, что есть один Zval, который указывает две записи в таблице символов: 'a' и 'b'. Но в качестве альтернативы можно было бы сделать это (метод 2):

$a = null; 
$b = null; 

Наивно можно было бы ожидать, что это должно привести к двум различным zvals, каждый указал на одну запись в таблице символов.

ли из этого следует, что если вы хотите иметь большой массив, и многие элементы массива будут null, это более эффективно (с точки зрения ZVAL/использования памяти), чтобы создать $master_null переменную со значением null , а затем записать элементы null массива, назначив с помощью $master_null?

+0

Почему бы просто не попробовать? Кажется достаточно простым. – Halcyon

+0

@Frits: Я не знаю, как определить, какие zvals существуют из скрипта. Поведение PHP в каждом случае одинаково; внутренняя разница скрыта от пользователя. – Hammerite

+0

Но эффективные свойства памяти не будут скрыты от вас. Это то, что вы хотите знать правильно? – Halcyon

ответ

2

Рассмотрим этот скрипт:

$arr = array(); 
for ($i = 0; $i < 100000; $i++) $arr[] = null; 
echo memory_get_usage() . "\n"; 

, который на моей машине выходов: 21687696, что составляет 21 Мб используемой памяти , С другой стороны, используя это:

$master_null = null; 
$arr = array(); 
for ($i = 0; $i < 100000; $i++) $arr[] = $master_null; 
echo memory_get_usage() . "\n"; 

выходы: 13686832, что составляет 13 МБ. Основываясь на этой информации, вы можете предположить, что, поскольку использование памяти является вашей проблемой, на самом деле лучше использовать переменную «главный нуль». Однако вам все равно нужно иметь все элементы в массиве, и каждая запись в HashTable (внутреннее представление массивов) также занимает некоторую память.

Если вы хотите копать глубже в zvals и ссылках, я предлагаю использовать функцию debug_zval_dump. Используя его, вы можете увидеть, какие переменные одни и те же ZVAL:

$a = $b = $c = $d = "abc"; 
debug_zval_dump($a); 
$x = $y = $z = $w = null; 
debug_zval_dump($x); 
$q = null; 
debug_zval_dump($q); 

, который выводит:

string(3) "abc" refcount(5) 
NULL refcount(5) 
NULL refcount(2) 

И это означает, что, хотя переменные $ х и $ д являются NULL, они не являются такой же zval. Но $ x и $ y имеют один и тот же zval, потому что они назначены друг другу. Я считаю, что вы знаете о функции debug_zval_dump, но если нет, убедитесь, что вы внимательно прочитали объяснение refcount на http://php.net/manual/en/function.debug-zval-dump.php.

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

0

Не все, что достигнет, это то, что у вас будет дополнительная переменная под названием $master_null. Все они указывают на нуль. Наличие каждой точки до $master_null - это то же самое.

+0

Я не уверен, что вы поняли суть моего вопроса. – Hammerite

1

Из того, что я понимаю, PHP zval-контейнеры имеют логику подсчета ссылок. Таким образом, каково мое впечатление, если вы используете ссылки, то есть & $ master_null, чтобы инициализировать все значения NULL, я думаю, что это экономит ваше пространство, то есть все элементы NULL точек массива относятся к той же ссылке на контейнер zval.

Вот пример:

# php -r '$var1 = NULL; $var2 = $var1; $var3 = $var1; debug_zval_dump(&$var1); debug_zval_dump(&$var2); debug_zval_dump(&$var3);' 
&NULL refcount(2) 
&NULL refcount(2) 
&NULL refcount(2) 

Вы можете прочитать больше о reference counting basis РНР здесь:

что-то стоит прочитать по этой ссылке находится:

PHP is smart enough not to copy the actual variable container 
when it is not necessary. Variable containers get destroyed 
when the "refcount" reaches zero. The "refcount" gets decreased by 
one when any symbol linked to the variable container leaves the 
scope (e.g. when the function ends) or when unset() is called on a symbol. 

Таким образом, каждый раз, когда вы используете & $ master_null, это «refcount» увеличивается, и когда «refcount» достигает нуля, контейнер переменной удаляется из памяти.


Из выше комментарию примера здесь является использование памяти:

# php -r '$arr = array(); for ($i = 0; $i < 100000; $i++) $arr[] = null; echo memory_get_usage() . "\n";' 
11248372 
# php -r '$master_null = null; $arr = array(); for ($i = 0; $i < 100000; $i++) $arr[] = &$master_null; echo memory_get_usage() . "\n";' 
6848488 
# php -r '$master_null = null; $arr = array(); for ($i = 0; $i < 100000; $i++) $arr[] = $master_null; echo memory_get_usage() . "\n";' 
6848468 

 Смежные вопросы

  • Нет связанных вопросов^_^