Что лучше для освобождения памяти с помощью PHP: unset () или $var = null

Я понимаю, что второй избегает накладных расходов вызова функции (обновление, на самом деле является языковой конструкцией), но было бы интересно узнать, лучше ли один из них, чем другой. Я использую unset() для большей части моего кодирования, но я недавно просмотрел несколько респектабельных классов, найденных в сети, которые используют $var = null вместо.

есть ли предпочтительный, и каковы рассуждения?

12 ответов


это было упомянуто в unset страницы руководства в 2009:

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

если вы делаете $whatever = null; тогда вы переписываете переменные данные. Вы можете быстрее освободить / сжать память, но это может украсть циклы процессора из кода, который действительно нуждается в них раньше, что приведет к более длительному общему времени выполнения.

(начиная с 2013 года, что unset man page больше не включайте этот раздел)

обратите внимание, что до php5.3, Если у вас есть два объекта в круговой ссылке, например, в отношениях "родитель-потомок" вызов unset () для родительского объекта не освобождает память используется для родительской ссылки в дочернем объекте. (Также память не будет освобождена, когда родительский объект будет собран в мусор.) (33595 ошибка)


на вопрос "разница между unset и = null" подробно описаны некоторые отличия:


unset($a) также удаляет $a из таблицы символов; например:

$a = str_repeat('hello world ', 100);
unset($a);
var_dump($a);

выходы:

Notice: Undefined variable: a in xxx
NULL

но когда $a = null is используется:

$a = str_repeat('hello world ', 100);
$a = null;
var_dump($a);
Outputs:

NULL

кажется,$a = null немного быстрее, чем его unset() counterpart: обновление записи таблицы символов, по-видимому, быстрее, чем ее удаление.


  • когда вы пытаетесь использовать несуществующую (unset) переменная, будет вызвана ошибка, и значение для выражения переменной будет равно null. (Потому что, что еще должен делать PHP? Каждое выражение должно привести к некоторому значению.)
  • переменной с null, назначенным ему, по-прежнему является совершенно нормальной переменной.

unset на самом деле не функция, а языковая конструкция. Это не более чем вызов функции return или include.

помимо проблем с производительностью, используя unset делает намерение гораздо понятнее.


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

Это из личного опыта и других. См. комментарии функции unset() здесь.

Я лично использую unset () между итерациями в цикле, так что мне не нужно иметь задержку стека в размере yo-yo'D. Данные исчезли, но след остался. На следующей итерации память уже берется php и, таким образом, быстрее инициализировать следующую переменную.


<?php
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    $a = NULL;
}
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds\r\n";



$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    unset($a);
}
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds\r\n";
?>

за то, что кажется, что" = null " быстрее.

в PHP 5.4 результаты:

  • заняло 0,88389301300049 секунды
  • заняло 2.1757180690765 секунд

в PHP 5.3 результаты:

  • заняло 1,7235369682312 секунды
  • потребовалось 2.9490959644318 секунд

в PHP 5.2 результаты:

  • заняло 3,0069220066071 секунды
  • взял 4.7002630233765 секунды!--7-->

результаты PHP 5.1:

  • заняло 2,6272349357605 секунды
  • заняло 5.0403649806976 секунд

вещи начинают выглядеть по-другому с PHP 5.0 и 4.4.

5.0:

  • заняло 10.038941144943 секунды
  • потребовалось 7.0874409675598 секунд

4.4:

  • заняло 7.5352551937103 секунды
  • взял 6.6245851516724 секунды!--7-->

имейте в виду, что microtime (true) не работает в PHP 4.4, поэтому мне пришлось использовать пример microtime_float, приведенный в php.net/microtime / Пример #1.


это имеет значение с элементами массива.

рассмотрим такой пример

$a = array('test' => 1);
$a['test'] = NULL;
echo "Key test ", array_key_exists('test', $a)? "exists": "does not exist";

здесь ключ "test" все еще существует. Однако, в этом примере

$a = array('test' => 1);
unset($a['test']);
echo "Key test ", array_key_exists('test', $a)? "exists": "does not exist";

ключ больше не существует.


он работает по-другому для переменных, скопированных по ссылке:

$a = 5;
$b = &$a;
unset($b); // just say $b should not point to any variable
print $a; // 5

$a = 5;
$b = &$a;
$b = null; // rewrites value of $b (and $a)
print $a; // nothing, because $a = null

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

используйте time_nanosleep, чтобы включить GC для сбора памяти. Установка переменной в null является желательным.

протестировано на рабочем сервере, первоначально задание потребляло 50 МБ, а затем было остановлено. После nanosleep был использован 14MB был постоянное потребление памяти.

следует сказать, что это зависит от поведения GC, которое может измениться от версии PHP до версии. Но он отлично работает на PHP 5.3.

например. этот образец (код взят из формы VirtueMart2 Google feed)

for($n=0; $n<count($ids); $n++)
{
    //unset($product); //usefull for arrays
    $product = null
    if( $n % 50 == 0 )
    {
        // let GC do the memory job
        //echo "<mem>" . memory_get_usage() . "</mem>";//$ids[$n];
        time_nanosleep(0, 10000000);
    }

    $product = $productModel->getProductSingle((int)$ids[$n],true, true, true);
    ...

Я все еще сомневаюсь в этом, но я пробовал это в своем скрипте, и я использую xdebug, чтобы узнать, как это повлияет на использование памяти приложения. Скрипт устанавливается на мою функцию следующим образом:

function gen_table_data($serv, $coorp, $type, $showSql = FALSE, $table = 'ireg_idnts') {
    $sql = "SELECT COUNT(`operator`) `operator` FROM $table WHERE $serv = '$coorp'";
    if($showSql === FALSE) {
        $sql = mysql_query($sql) or die(mysql_error());
        $data = mysql_fetch_array($sql);
        return $data[0];
    } else echo $sql;
}

и я добавляю unset непосредственно перед return код и он дает мне : 160200 затем я пытаюсь изменить его с $sql = NULL и это дает мне: 160224:)

но есть что-то уникальное в этом сравнении, когда я не использую unset() или NULL, xdebug дает мне 160144 в качестве памяти использование

Итак, я думаю, что предоставление строки для использования unset() или NULL добавит процесс в ваше приложение, и будет лучше остаться origin с вашим кодом и уменьшить переменную, которую вы используете, насколько это возможно .

поправьте меня, если я ошибаюсь, спасибо


Я создал новый тест производительности для unset и =null, потому что, как упоминалось в комментариях, здесь написано ошибка (воссоздание элементов). Я использовал массивы, как вы видите, теперь это не имело значения.

<?php
$arr1 = array();
$arr2 = array();
for ($i = 0; $i < 10000000; $i++) {
    $arr1[$i] = 'a';
    $arr2[$i] = 'a';
}

$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $arr1[$i] = null;
}
$elapsed = microtime(true) - $start;

echo 'took '. $elapsed .'seconds<br>';

$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    unset($arr2[$i]);
}
$elapsed = microtime(true) - $start;

echo 'took '. $elapsed .'seconds<br>';

но я могу проверить его только на сервере PHP 5.5.9, здесь результаты: - заняло 4.4571571350098 секунд - заняло 4.4425978660583 секунды

предпочитаю unset из соображений читабельности.


unset код если не освобождать непосредственную память все еще очень полезно и было бы хорошей практикой делать это каждый раз, когда мы передаем шаги кода перед выходом из метода. обратите внимание, что речь идет не об освобождении немедленной памяти. непосредственная память для CPU, как насчет вторичной памяти, которая является ОЗУ.

и это также решает проблему предотвращения утечек памяти.

пожалуйста, посмотрите это ссылка на сайт http://www.hackingwithphp.com/18/1/11/be-wary-of-garbage-collection-part-2

Я использую unset в течение длительного времени.

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

$data['tesst']='';
$data['test2']='asdadsa';
....
nth.

и just unset($data); чтобы освободить все переменные использования.

см. раздел, связанный с unset

насколько важно отключить переменные в РНР?

[ошибка]


для записи и за исключением времени, которое требуется:

<?php
echo "<hr>First:<br>";
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n"; 
echo "<hr>Unset:<br>";
unset($x);
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n"; 
echo "<hr>Null:<br>";
$x=null;
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n";

echo "<hr>function:<br>";
function test() {
    $x = str_repeat('x', 80000);
}
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n"; 

echo "<hr>Reasign:<br>";
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n"; 

возвращает

First:
438296
438352
Unset:
438296
438352
Null:
438296
438352
function:
438296
438352
Reasign:
438296
520216 <-- double usage.

Заключение, Как null, так и unset свободной памяти, как ожидалось (не только в конце выполнения). Кроме того, переназначение переменной содержит значение дважды в какой-то момент (520216 против 438352)


PHP 7 уже работает над такими проблемами управления памятью и ее сокращением до минимального использования.

<?php
  $start = microtime(true);
  for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    $a = NULL;
  }
  $elapsed = microtime(true) - $start;

  echo "took $elapsed seconds\r\n";

  $start = microtime(true);
  for ($i = 0; $i < 10000000; $i++) {
     $a = 'a';
     unset($a);
  }
  $elapsed = microtime(true) - $start;

  echo "took $elapsed seconds\r\n";

?>

PHP 7.1 Outpu:

заняло 0,16778993606567 секунды заняло 0,16630101203918 секунды