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

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

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

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

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

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

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

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

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


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


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

 $a = str_repeat('hello world ', 100); unset($a); var_dump($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? Каждое выражение должно приводить к некоторому значению.)
  • Однако переменная с присвоенным ей значением null все еще является совершенно нормальной переменной.

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

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

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

Это было из личного опыта и других. См. Комментарии функции 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"; ?> с <?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.

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

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

 $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"; с $a = array('test' => 1); unset($a['test']); echo "Key test ", array_key_exists('test', $a)? "exists": "does not exist"; 

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

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

 $a = 5; $b = &$a; unset($b); //just say $b should not pointer to any var print $a; // 5 $a = 5; $b = &$a; $b = null; //rewrite value of $b (and $a) print $a; // nothing, because $a = null с $a = 5; $b = &$a; unset($b); //just say $b should not pointer to any var print $a; // 5 $a = 5; $b = &$a; $b = null; //rewrite value of $b (and $a) print $a; // nothing, because $a = null 

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

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

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

Я создал новый тест производительности для 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 $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 code, если не освободить оперативную память, по-прежнему очень полезен и будет хорошей практикой делать это каждый раз, когда мы передаем шаги кода перед тем, как выйти из метода. обратите внимание на то, что это не освобождение памяти. непосредственная память для CPU, а о вторичной памяти – ОЗУ.

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

см. эту ссылку http://www.hackingwithphp.com/18/1/11/be-wary-of-garbage-collection-part-2

Я давно использую unset.

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

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

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

см. соответствующую тему для отмены

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

[Ошибка]

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

 <?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"; с <?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)