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

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

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

Ответ 1

На странице unset manual было указано:

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

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

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

Обратите внимание, что до 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:

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

NULL

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


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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

<?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 секунд

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

  • принял 2.6272349357605 секунд
  • заняло 5.0403649806976 секунд

С PHP 5.0 и 4.4 все начинает выглядеть иначе.

5,0:

  • занял 10.038941144943 секунды
  • взял 7.0874409675598 секунд

4.4

  • взял 7.5352551937103 секунды
  • взял 6.6245851516724 секунд

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

Ответ 5

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

Рассмотрим этот пример

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

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

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

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

Ответ 6

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

$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

Ответ 7

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

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

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

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

например. этот пример (код, взятый из файла VirtueMart2 google)

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

Ответ 8

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

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 добавит процесс в ваше приложение, и будет лучше оставаться источником с вашим кодом и уменьшить переменную, которую вы используете, насколько это возможно.

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

Ответ 9

Я создал новый тест производительности для 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 для удобства чтения.

Ответ 10

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?

[ошибка]

Ответ 11

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

<?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.

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