En effet, PHP est un langage qui ne permet pas au développeur de gérer lui-même la mémoire utilisée par son code.

C’est en effet ce que l’on appelle dans le monde des langages de programmation le garbage collector qui se charge de gérer la mémoire requise par le fonctionnement du code de manière optimum (du moins en théorie).

Et si le développeur a bien la possibilité d’altérer son comportement à l’aide des fonctions gc_*, elles ne sont utiles que dans un contexte très particulier et en conséquence elles n’autorisent en aucune façon une gestion fine de la mémoire similaire à celle que permet un langage comme le C.

Dans un tel contexte, il est donc complètement inutile de connaître la quantité de mémoire requise pour le stockage d’une structure zval ou de toute autre structure manipulée par PHP en interne, car vous ne pourrez rien faire pour optimiser la façon dont le langage utilise cette mémoire (à moins que vous ne souhaitiez briller en société en étalant votre science, encore que je pense que ce genre d’information ne passionne pas les foules).

Au mieux, vous pouvez faire des appels à unset() à des endroits stratégiques de votre code pour indiquer au « garbage collector » que vous n’avez plus besoin d’une variable et qu’en conséquence il peut faire le ménage.

Il est par exemple parfois pertinent de le faire à l’issue d’une boucle foreach, puisque la variable dans laquelle sont stockées les différentes variables du tableau ou de l’objet sur laquelle la boucle est effectuée n’est pas détruite automatiquement à l’issue de la boucle.

<?php
foreach ($anArrayWithBiGobjectInIt as $anObject)
{
// do something with $anObject
}
// $anObject contient le dernier objet du tableau $anArrayWithBiGobjectInIt.
// Il est donc pertinent de demander sa destruction
unset($anObject)
?>

Cependant, vous n’aurez aucune garantie que la mémoire utilisée sera effectivement libérée lors de l’appel à unset().

En effet, la mémoire ne sera libérée que lorsqu’il n’y aura plus de référence vers la variable concernée, et même si c’est le cas, le garbage collector ne libérera peut-être pas l’espace mémoire correspondant immédiatement afin d’optimiser la gestion globale de la mémoire.

De plus, d’une version de PHP à une autre, le fonctionnement du garbage collector peut être plus ou moins efficace.

Un même code peut donc avoir une empreinte mémoire qui évolue d’une manière totalement différente en fonction de la version de PHP utilisée.

Pour preuve, en moyenne, PHP 5.3 réduit significativement la consommation mémoire d’un script par rapport à 5.2, 5.4 PHP fait encore mieux en réduisant encore cette consommation mémoire de 30 % et la future version 5.5 semble prometteuse de ce point de vue.

Il est donc totalement illusoire et stupide d’espérer contrôler ou optimiser la façon dont PHP utilise la mémoire.

Et si vous décidez tout de même de le faire à l’aide du peu d’outils que PHP met à votre disposition, je peux vous dire par expérience (oui, il m’arrive aussi d’être stupide) que vous avez plus de chance d’empirer la situation que de l’améliorer.

Cependant, cela ne veut pas dire que vous ne pouvez rien faire pour éviter d’avoir une consommation de mémoire excessive.

En effet, si le langage ne vous permet pas d’optimiser la consommation mémoire de votre code, vous pouvez cependant faire en sorte que vos processus PHP aient une empreinte mémoire optimale et concevoir votre code de façon à réduire au maximum la quantité de mémoire requise pour son fonctionnement.

Ainsi, pour diminuer l’empreinte mémoire de vos processus PHP, vous pouvez notamment :

  • Compiler PHP vous-même afin d’avoir un exécutable optimisé au maximum pour l’architecture sur laquelle il sera utilisé
  • Supprimer toutes les extensions qui ne sont pas absolument indispensables au fonctionnement de votre code.
  • Utiliser la version la plus récente possible en fonction de votre contexte technique.

Et au niveau de votre code, vous pouvez par exemple :

  • Faire appel à unset() lorsque c’est utile, comme nous l’avons vu précédemment afin d’aider le garbage collector à faire son travail au mieux.
  • Utiliser un système d’autochargement de classe afin de ne faire interpréter à PHP que le code absolument nécessaire au fonctionnement de vos scripts.
  • Découpler au maximum vos classes afin qu’elle n’ait qu’une et une seule responsabilité et pouvoir ainsi charger en mémoire uniquement le code strictement nécessaire pour répondre au besoin et ainsi éviter les classes fourre-tout.
  • Mettre en œuvre l’algorithme le mieux adapté pour résoudre votre problème en évitant, par exemple, de charger intégralement en mémoire un fichier pouvant contenir un gros volume de données pour l’interpréter.
  • Ne pas transférer l’intégralité des enregistrements de votre serveur de base de données vers PHP lorsque cela est possible.
  • Éviter dans la mesure du possible les appels récursifs qui peuvent se révéler très gourmands en mémoire.

Évidemment, toutes ces solutions sont cumulables et si malgré tout cela vous n’êtes pas satisfait de la consommation mémoire de vos scripts, il vous faudra soit ajouter des barrettes de mémoire dans vos machines ou abandonner PHP et recourir à un langage plus efficace de ce point de vue ou vous permettant effectivement de la gérer !