Ramasse-miettes (Garbage Collection)
PHP Manual

Considerations sur les performances

Nous avons déja vu dans les sections précédentes que la collecte des racines probables avait un impact très léger sur les performances, mais c'est lorsqu'on compare PHP5.2 à PHP5.3. Même si l'enregistrement des racines probables est plus lent que de pas les enregistrer du tout, comme dans PHP5.2, d'autres changements durant l'éxécution de PHP5.3 font de cette opération une opération quasi indolore au niveau des performances.

Il y a deux axes pour étudier les performances avec GC. D'abord l'empreinte mémoire et ensuite le temps d'éxécution pour nettoyer la mémoire. Nous allons étudier ces deux axes.

Empreinte mémoire réduite

D'abord, la raison principale de l'implémentation du mécanisme de collecte des déchets est la réduction de la mémoire consommée en nettoyant les références circulaires aussitôt que possible. Dans PHP, ceci arrive lorsque le tampon de racines est plein, ou lorsque la fonction gc_collect_cycles() est appelée. Sur le graphe ci-après, nous affichons l'utilisation mémoire d'un script dans PHP5.2 et PHP5.3, en excluant la mémoire obligatoire que PHP consomme pour lui-même au démarrage.

Exemple #1 Exemple d'utilisation mémoire

<?php
class Foo
{
    public 
$var '3.141592654';
}

$baseMemory memory_get_usage();

for ( 
$i 0$i <= 100000$i++ )
{
    
$a = new Foo;
    
$a->self $a;
    if ( 
$i 500 === )
    {
        echo 
sprintf'%8d: '$i ), memory_get_usage() - $baseMemory"\n";
    }
}
?>
Comparaison de la consommation mémoire entre PHP 5.2 et PHP 5.3

L'exemple est étuidé pour, nous allons créer un objet possédant un attribut le référençant lui-même. Lorsque la variable $a dans le script est réassignée à la prochaine itération, une fuite mémoire apparaitra. Dans ce cas, les deux conteneurs zval fuient (la zval de l'objet et celle de l'attribut), mais seulement une racine possible est trouvée : la variable qui a été supprimée. Lorsque le tampon de racines est plein après 10.000 itérations (un total de 10.000 racines possibles), le mécanisme de collection des déchets entre en jeu et libère la mémoire associée à ces racines probables. Cela se voit très clairement sur les graphes d'utilisation mémoire de PHP5.3. Après chaques 10.000 itérations, le mécanisme se déclenche et libère la mémoire associée aux variables références circulaires. Le diagramme montre que l'utilisation maximale de mémoire de PHP5.3 est d'environ 9Mo là où PHP5.2 n'arrête pas d'en consommer.

Ralentissement durant l'exécution

Le second point concernant les performances du mécanisme de collecte des déchets (GC) est le temps pris par le mécanisme pour libérer la mémoire "gaspillée". Pour voir cet impact, nous allons modifier le script précédent afin d'avoir un nombre d'itérations beaucoup plus élevé. Le script ressemble à:

Exemple #2 Impact de GC sur les performances

<?php
class Foo
{
    public 
$var '3.141592654';
}

for ( 
$i 0$i <= 1000000$i++ )
{
    
$a = new Foo;
    
$a->self $a;
}

echo 
memory_get_peak_usage(), "\n";
?>

Nous allons lancer ce script 2 fois, une fois avec zend.enable_gc à on, et une fois à off:

Exemple #3 Lancement du script ci-dessus

time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
# and
time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php

Sur ma machine, la première commande semble durer tout le temps 10,7 secondes, alors que la seconde commande prend environ 11,4 secondes. Un ralentissement de 7% environ. Cependant, la quantité totale de mémoire utilisée par le script est réduite de 98% passant de 931Mo à 10Mo. Ce benchmark n'est pas très scientifique ou même représentatif d'applications réelles, mais il démontre concrètement en quoi le mécanisme de collecte des déchets peut être utile concernant la consommation mémoire. Le bon point est que le ralentissement est toujours de 7%, dans le cas particulier de ce script, alors que la mémoire restaurée sera de plus en plus importante au fur et à mesure que des références circulaires apparaitront durant l'éxécution.

Statistiques internes du GC de PHP

Il est possible d'obtenir quelques informations concernant le mécanisme de collecte des déchets interne à PHP. Mais pour cela, il faut recompiler PHP avec le support du benchmarking et de la collection de données. Vous devrez passer la variable d'environnement CFLAGS avec -DGC_BENCH=1 avant de lancer ./configure. L'exemple suivant démontre cela:

Exemple #4 Recompiler PHP pour le support du benchmark du GC

export CFLAGS=-DGC_BENCH=1
./config.nice
make clean
make

Lorsque vous ré-éxécutez le code du script ci-dessus avec un PHP fraichement reconstruit, vous devriez voir le résultat suivant après l'éxecution:

Exemple #5 Statistiques GC

GC Statistics
-------------
Runs:               110
Collected:          2072204
Root buffer length: 0
Root buffer peak:   10000

      Possible            Remove from  Marked
        Root    Buffered     buffer     grey
      --------  --------  -----------  ------
ZVAL   7175487   1491291    1241690   3611871
ZOBJ  28506264   1527980     677581   1025731

Les statistiques les plus descriptives sont affichées dans le premier bloc. Vous voyez que le mécanisme de collecte des dechets a été déclenché 110 fois, et au total ce sont plus de 2 millions d'allocations mémoires qui ont été libérées durant ces 110 passages. Dès lors que le mécanisme est intervenu une seule fois, le pic du buffer racine est toujours de 10000.

Conclusion

De manière générale, la collection des dechets en PHP ne causera un ralentissement que lorsque le cycle tournera, ainsi dans les scripts normaux il ne devrait pas y avoir de ressenti de ce ralentissement.

Cependant, lorsque le cycle de collection de déchets sera enclenché dans des scripts normaux, la réduction de l'empreinte mémoire permettra alors d'éxécuter plus de scripts en parallèle.

Les avantages se sentent plus dans le cas de scripts démons ou devant tourner longtemps. Aussi, concernant les applications » PHP-GTK qui souvent tournent plus longtemps que des scripts pour le Web, le nouveau mécanisme devrait réduire significativement les fuites mémoires sur le long terme.


Ramasse-miettes (Garbage Collection)
PHP Manual