web-dev-qa-db-fra.com

Quoi de mieux pour libérer de la mémoire avec PHP: unset () ou $ var = null

Je me rends compte que le second évite la surcharge d'un appel de fonction ( update , est en fait une construction de langage), mais il serait intéressant de savoir si l'une est meilleure que l'autre. J'utilise unset() pour la plupart de mes opérations de codage, mais j'ai récemment examiné quelques classes respectables trouvées hors réseau qui utilisent plutôt $var = null.

Y at-il un préféré, et quel est le raisonnement?

231
alex

Il a été mentionné dans la page du manuel unset en 2009 :

unset() fait exactement ce que son nom l'indique - désactive une variable. Cela ne force pas la libération immédiate de la mémoire. Le ramasse-miettes de PHP le fera à sa guise - par intention dès que possible, car ces cycles de processeur ne sont de toute façon pas nécessaires, ou jusqu'à ce que le script manque de mémoire, peu importe ce qui se passe en premier.

Si vous faites $whatever = null;, vous réécrivez les données de la variable. La mémoire peut être libérée/réduite plus rapidement, mais le programme qui en a vraiment besoin plus rapidement peut être volé plus rapidement, ce qui allonge le temps d’exécution.

(Depuis 2013, cette unset page de manuel n'inclut plus cette section)

Notez que jusqu'à php5.3, si vous avez deux objets dans une référence circulaire , comme dans une relation parent-enfant, appeler unset () sur l'objet parent ne libérera pas la mémoire utilisée pour la référence parente dans l'enfant objet. (La mémoire ne sera pas libérée non plus lorsque l'objet parent sera ramassé.) ( bug 33595 )


La question " différence entre unset et = null " détaille quelques différences:


unset($a) supprime également $a de la table des symboles; par exemple:

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

Les sorties:

Notice: Undefined variable: a in xxx
NULL

Mais quand $a = null est utilisé:

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

NULL

Il semble que $a = null soit un peu plus rapide que son équivalent unset(): mettre à jour une entrée de la table des symboles semble être plus rapide que de la supprimer.


  • lorsque vous essayez d'utiliser une variable inexistante (unset), une erreur est déclenchée et la valeur de l'expression de la variable est null. (Parce que, quoi d'autre devrait PHP faire? Chaque expression doit donner une valeur.) 
  • Une variable avec null assignée est toujours une variable parfaitement normale.
220
VonC

unset n'est pas réellement une fonction, mais un construction du langage. Ce n'est pas plus un appel de fonction qu'un return ou un include.

Outre les problèmes de performances, l'utilisation de unset rend le code intention de votre code beaucoup plus clair.

44
Alex Barrett

En faisant un unset (()) sur une variable, vous avez essentiellement marqué la variable pour «garbage collection» (PHP n'en a pas vraiment, mais par exemple) afin que la mémoire ne soit pas immédiatement disponible. La variable n'héberge plus les données, mais la pile reste à la taille la plus grande. Faire la méthode null supprime les données et réduit la mémoire de pile presque immédiatement.

Cela vient d’expériences personnelles et d’autres aussi. Voir les commentaires de la fonction unset () ici .

Personnellement, j'utilise unset () entre les itérations d'une boucle pour ne pas avoir à attendre que la pile ait une taille yo-yo'd. Les données ont disparu, mais l'empreinte reste. À la prochaine itération, php utilise déjà la mémoire et initialise plus rapidement la variable suivante.

34
William Holroyd
<?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";
?>

Il semble que "= null" soit plus rapide.

Résultats de PHP 5.4:

  • a pris 0.88389301300049 secondes
  • a pris 2.1757180690765 secondes

Résultats PHP 5.3:

  • a pris 1.7235369682312 secondes
  • a pris 2.9490959644318 secondes

Résultats de PHP 5.2:

  • a pris 3.0069220066071 secondes
  • a pris 4.7002630233765 secondes

Résultats PHP 5.1:

  • a pris 2.6272349357605 secondes
  • a pris 5.0403649806976 secondes

Les choses commencent à être différentes avec PHP 5.0 et 4.4.

5.0:

  • a pris 10.038941144943 secondes
  • pris en 7.0874409675598 secondes

4.4:

  • a pris 7.5352551937103 secondes
  • a pris 6.6245851516724 secondes

Gardez à l'esprit que microtime (true) ne fonctionne pas dans PHP 4.4, j'ai donc dû utiliser l'exemple microtime_float donné dans php.net/microtime/Example # 1.

25
user1469439

Cela fait une différence avec les éléments de tableau.

Considérez cet exemple

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

Ici, la clé 'test' existe toujours. Cependant, dans cet exemple

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

la clé n'existe plus.

18
auris

Cela fonctionne différemment pour les variables copiées par référence:

$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
17
RiaD

En ce qui concerne les objets, en particulier dans le scénario de chargement différé, il convient de considérer que le récupérateur de mémoire fonctionne dans des cycles de processeur inactifs. Par conséquent, le fait de supposer que vous rencontrez des problèmes lorsque de nombreux objets chargent une petite pénalité de temps résoudra la libération de mémoire.

Utilisez time_nanosleep pour permettre au CPG de collecter de la mémoire . Il est souhaitable de définir la variable sur null.

Testé sur le serveur de production, à l'origine, le travail consommait 50 Mo puis était arrêté . Après l'utilisation de nanosleep, 14 Mo correspondaient à une consommation de mémoire constante.

Il faut dire que cela dépend du comportement du CPG, qui peut changer de version PHP à version . Mais cela fonctionne sous PHP 5.3.

par exemple. cet exemple (code pris sous forme de flux Google VirtueMart2)

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

J'en doute toujours, mais je l'ai essayé avec mon script et j'utilise xdebug pour savoir en quoi cela affectera l'utilisation de la mémoire de mon application . Le script est défini sur ma fonction comme suit:

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;
}

Et j'ajoute unset juste avant le code return et il me donne: 160200 Puis j'essaie de le changer avec $sql = NULL et cela me donne: 160224 :)

Mais il y a quelque chose d'unique sur ce comparatif quand je n'utilise pas unset () ou NULL, xdebug me donne 160144 comme utilisation de la mémoire

Donc, je pense que donner une ligne à utiliser unset () ou NULL ajoutera un processus à votre application et il sera préférable de rester Origin avec votre code et de réduire la variable que vous utilisez aussi efficacement que possible.

Corrigez-moi si je me trompe, merci

3
Anggie Aziz

J'ai créé un nouveau test de performance pour unset et =null, car, comme indiqué dans les commentaires, l'erreur écrite ici est une erreur (la recréation des éléments). J'ai utilisé des tableaux, comme vous voyez, cela importait moins maintenant.

<?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>';

Mais je ne peux le tester que sur un serveur PHP 5.5.9, voici les résultats: - a pris 4.4571571350098 secondes - a pris 4.4425978660583 secondes

Je préfère unset pour des raisons de lisibilité.

2
Michael B.

unset code sinon libérer la mémoire immédiate est toujours très utile et serait une bonne pratique de le faire chaque fois que nous passons des étapes de code avant de quitter une méthode. notez qu'il ne s'agit pas de libérer de la mémoire immédiate. La mémoire immédiate est destinée au processeur, qu’en est-il de la mémoire secondaire qui est de la RAM.

et cela concerne également la prévention des fuites de mémoire. 

veuillez consulter ce lien http://www.hackingwithphp.com/18/1/11/be-wary-of-garbage-collection-part-2

j'utilise unset depuis longtemps maintenant.

une meilleure pratique comme celle-ci dans le code consiste à désinstaller instantanément toutes les variables déjà utilisées en tant que tableau. 

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

et just unset($data); pour libérer toutes les utilisations de variables.

s'il vous plaît voir le sujet connexe pour désactiver

Quelle est l'importance de supprimer des variables en PHP?

[punaise]

1
zero8

PHP 7 a déjà travaillé sur de tels problèmes de gestion de la mémoire et son utilisation réduite à minimale.

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

a pris 0.16778993606567 secondes .__ a pris 0,16630101203918 secondes

1
Swapnil

Pour mémoire, en excluant le temps qu'il faut:

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

Il retourne

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

Conclusion: mémoire libre nulle et non définie comme prévu (pas seulement à la fin de l'exécution). De plus, la réaffectation d'une variable conserve la valeur deux fois à un moment donné (520216 contre 438352)

0
magallanes