Script PHP : Problème de mémoire

theJB

WRInaute occasionnel
Je remarque un truc étrange sur mon serveur..

J'ai un script php qui parse un flux xml (>1Go) avec xml reader. Le script prend 5min a s'executer et grignote petit à petit la RAM disponible. Le serveur a 2Gb de RAM, et à la fin du script, 1.8Gb sont pris.

Et mon problème, que je trouve assez bizard, c'est que une fois l'execution terminée les 1.8Gb du scripts restent occupés.. même une heure après.. et je comprends pas.

Faut-il faire qqch comme un mysql_free_result mais pour php?

Et encore un truc bizard, j'utilise top en SSH pour connaitre la mémoire occupée par mon script, et d'après cette commande, mon scripts n'utilise jamais plus de 3% de la mémoire..

Bref je comprends pas..
 

Bool

WRInaute passionné
Hello,

le script en question tu le lances via Apache ? Si c'est le cas, il y a des chances pour qu'il faille relancer Apache après pour libérer la mémoire (oui c'est chiant, c'est pour ça que ce genre de traitement est généralement fait via CLI).

Simple vérification : tu ne charges tout de même pas tout le contenu du fichier en mémoire, si ?

Sinon coté fuite mémoire, utilises-tu preg_match() dans ta boucle ?
En effet sous Debian PHP est compilé avec une vieille version de la librairie PCRE qui a de vilaines fuites mémoire selon les expressions utilisées.
 

theJB

WRInaute occasionnel
Oui, j'utilise apache pour le script php.

Mais, je ne mets pas le tout flux en mémoire (heureusement :) ). Simplexml met le flux en mémoire, moi j'utilise xmlreader justement car il fonctionne en mode pull avec un pointeur qui dépile au fur et à mesure le feed, sans avoir à en stocker l'intérgralité en memoire.

D'après toi, l'execution en CLI de mon script me ferait libérer la mémoire automatiquement sans rien faire?


Autre remarque, quand je relance le script une deuxième fois, il ne reste plus que 0,2 Go de libre en RAM, mais paradoxalement tout ce passe bien, alors que la fois d'avant il m'avait pris 1,8Go..

(PS. pas de preg_match utilisé)
 

Bool

WRInaute passionné
Oui, si PHP est lancé en CLI la mémoire qu'il consomme est libérée à la fin du traitement (mais ce n'est pas une raison pour consommer autant non plus). De plus via CLI tu devrais voir plus facilement la consommation mémoire "réelle" du processus.

Je connais le fonctionnement de XMLReader, mais on ne sait jamais, on voit un peu de tout ici ;) En tous cas que ce soit un bug interne à PHP ou un bug lié à ton script, tu as sérieuse fuite quelque part.

Essayes de débugger ça à coup de memory_get_usage().
 

theJB

WRInaute occasionnel
Voila ce que me donne le memory_get_usage() : 44496 ...
Et ce en plein execution du script..

Je teste de suite la commande en CLI
 

theJB

WRInaute occasionnel
Bon j'ai testé en CLI, à la fin du script, pas de libération de la mémoire, et idem en restartant apache, je dois à chq fois rebooter le serveur.

J'ai essayé avec une version du script simplifé, j'ai toujours le même problème.

Et voila le code du script simplifié :

Code:
 $reader = new XMLReader();
 $reader->open('ftp_feeds/feed_big.xml');

 while ($reader->read()) 
 { 

 }
 $reader->close();
 
 unset($reader);

Tu as une idée? c'est xmlreader qui a un pb?
 

Bool

WRInaute passionné
T'es sûr de ton coup là ? Je fais ce genre de choses depuis longtemps avec des fichiers XML assez gros (400Mo le plus gros), et ça ne pose aucun soucis le script ne consomme rien (ou presque).

Ton script ne contient que ça ? Et... comment mesures-tu la consommation mémoire avant, pendant et après le script ?
 

theJB

WRInaute occasionnel
Voila comment je procede :
- je lance le script de parsing dans une fenetre
- je lance le script qui m'affiche la mémoire dans une autre

Avec top sous ssh, mon script n'occupe jamais plus de 3% de mémoire (sur la ligne associée à son processus), mais pourtant la mémoire (indiquée par les 1ères lignes, avec la charge CPU) se fait grignoter petit à petit jusqu'à presque 2Gb. Et ensuite, la mémoire n'est plus libérée.

Et je te confirme que mon script ne contient que ça.
 

Bool

WRInaute passionné
Donc en gros tu es en train de me dire que le cache disque de l'OS fonctionne correctement, c'est ça ?

Petit exemple :
Code:
Mem:   1036252k total,   645564k used,   390688k free,     3572k buffers
Swap:   505912k total,      116k used,   505796k free,   219952k cached

Tu fais référence au champ correspondant à mon 645564k used ?
Et ton champ 219952k cached il ne serait pas "énorme" à tout hasard ?

Essayes plutôt un free -m :
Code:
             total       used       free     shared    buffers     cached
Mem:          1011        630        381          0          3        214
-/+ buffers/cache:        411        600
Swap:          494          0        493

La ligne "-/+ buffers/cache" indique les valeurs ajustées en tenant compte du cache et autres buffers. Soit dans mon cas 411Mo d'utilisation et non 630Mo.
 

theJB

WRInaute occasionnel
avant

Code:
top - 16:27:02 up 1 min,  1 user,  load average: 1.22, 0.40, 0.14
Tasks: 142 total,   1 running, 141 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   2061660k total,   314300k used,  1747360k free,     4532k buffers
Swap:   922600k total,        0k used,   922600k free,   114552k cached

Code:
             total       used       free     shared    buffers     cached
Mem:          2013        312       1700          0          4        113
-/+ buffers/cache:        194       1819
Swap:          900          0        900

Après

Code:
top - 16:31:19 up 5 min,  2 users,  load average: 0.63, 0.39, 0.17
Tasks: 150 total,   1 running, 149 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.2%us,  0.0%sy,  0.0%ni, 99.8%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   2061660k total,  1824116k used,   237544k free,     7256k buffers
Swap:   922600k total,        0k used,   922600k free,  1607212k cached

Code:
             total       used       free     shared    buffers     cached
Mem:          2013       1781        231          0          7       1569
-/+ buffers/cache:        204       1808
Swap:          900          0        900

Effectivement le cache est énorme. Qu'est-ce que cela signifie?
 

Bool

WRInaute passionné
Bah rien d'anormal... c'est un cache disque. L'OS se sert de la mémoire non utilisée par les programmes pour conserver en mémoire une "copie du disque" ; ce qui lui permet d'accéder beaucoup moins souvent au disque.

Que ce soit avant ou après, tu n'as "que" 200Mo de mémoire utilisée.

Un peu de doc : http://fr.wikipedia.org/wiki/M%C3%A9moire_cache
 

theJB

WRInaute occasionnel
D'accord d'accord, j'ai donc passé mon aprèm sur un non-problème..

Petite question, la cache, elle se vide toute seule?

En tout cas merci du coup de main, j'y aurais passé ma semaine sans ton aide..
:)
 

Bool

WRInaute passionné
Le cache n'a jamais vraiment besoin d'être "vidé". Si une application a besoin de mémoire, alors oui Linux libérera un peu de son cache pour l'application en question. Mais sinon il n'a aucune raison de vider le cache puisqu'il s'agit de mémoire qui n'est pas utilisée sinon.

C'est d'ailleurs pour ça que sous Linux (et probablement d'autres OS de nos jours) la mémoire est quasiment toujours utilisée intégralement.

Et de rien ;)
 

YoyoS

WRInaute accro
Oui ca sert à rien de vouloir vider la ram. Vaut mieux limite qu'elle se remplisse entièrement et que tu puisses avoir accès à tout ce qu'elle a en mémoire en une fraction de seconde. Si elle a besoin de mettre quelque chose en mémoire, soit le serveur dédié swap, soit elle efface les data les plus anciennes, ou les moins utilisés.

Il y a quelquechose à changer pour que le système favorise la ram par rapport au swap, mais je sais plus quoi :D Tout façon, je crois que c'est mis par défaut, faut pas s'inquiéter :)

Si tu utilises plus les 1.8go de la ram et que le systeme a besoin de mémoire libre, ne t'inquiète pas, il va les virer si ca fait des heures que c'est plus utilisé :D
 

Bool

WRInaute passionné
Si tu utilises plus les 1.8go de la ram et que le systeme a besoin de mémoire libre, ne t'inquiète pas, il va les virer si ca fait des heures que c'est plus utilisé

Pourquoi diable effacerait il des données du cache s'il n'a pas besoin de la mémoire en question ? Cela ne servirait à rien, et serait susceptible de ralentir le système si quelques temps après les données sont à nouveau lues.

Le cache n'est nettoyé qu'en cas de "manque" de mémoire... et ce n'est certainement pas lui qui va déclencher le "swap", ce serait ridicule.
 

YoyoS

WRInaute accro
Bah il utilise 1.8Go pour une opération X, pourquoi les jeter tout de suite après alors que le système n'a pas besoin de stocker des informations en mémoires et qu'il ne sait pas si on aura encore besoin d'accéder aux informations dans la ram ? -__-

Le swap est déclenché selon comment est configuré le système et selon la fréquence d'utilisation ou l'ancienneté des informations présentes dans la ram et bien évidemment, la quantité de ram utilisée ;) .

NB: Bool je crois qu'en fait on est d'accord, mais t'as pas tout capté à ce que j'ai dit concernant le swap lol Ou alors tu voulais avoir le dernier mot :p

On voit que son swap est à 116k, autant dire qu'il s'en sert pas car il n'y a aucun souci de ram et qu'il trouve facilement de la place quand il doit y insérer de nouvelles informations :)

En fait je m'étais posé la même question avant, je trouvais ça aussi bizarre que ça ne libère pas tout de suite, mais c'est logique en fait :D
 

Bool

WRInaute passionné
Soit tu t'exprimes très mal, soit tu as une vision très approximative de la gestion de la mémoire.

Tu dis qu'après plusieurs heures de non utilisation il va vider le cache disque ; et je te réponds que c'est faux. Ca ne sert strictement à rien de vider le cache disque tant que le système ne vient pas à manquer de mémoire.
Les données du cache disque peuvent même rester des mois dans le cache ; ça ne pose aucun problème.

Et pour ce qui est du swap, j'indiquais qu'il serait ridicule pour l'OS d'y avoir recours si la cause de son manque de mémoire est le cache disque. Générer des écritures disque parce qu'on a un cache de lecture disque trop gros, ça ne te choque pas ?
 

YoyoS

WRInaute accro
Bool a dit:
Tu dis qu'après plusieurs heures de non utilisation il va vider le cache disque

Je sais pas ce que tu as dans les yeux mais prends vite une consultation ! Déjà je parlais de la ram et pas du cache disque qui est totalement différent! J'ai justement dit comme toi !!! Oui il va virer une partie des 1.8Go si le système a besoin de stocker de nouvelles informations une heure après !!!!!

Non je crois que je me suis exprimé très clairement, laisse moi te l'expliquer avant de me dire que c'est moi qui sait pas écrire :p

J'ai dit:
Si tu utilises plus les 1.8go de la ram et que le systeme a besoin de mémoire libre, ne t'inquiète pas, il va les virer si ca fait des heures que c'est plus utilisé Very Happy

Donc si après l'execution de ton programme qui utilisait 1.8go, 1h après, c'est sure que le système va se dire qu'il pourra virer ces informations s'il n'en a plus besoin afin d'y mettre de nouvelles informations.

J'ai simplement répondu à theJB qui disait avoir peur des 1.8go restant occupés, et je lui ai dit qu'il pouvait être sure que le système allait effacer une partie des 1.8Go restant pour de nouvelles données.

theJB a dit:
Et mon problème, que je trouve assez bizard, c'est que une fois l'execution terminée les 1.8Gb du scripts restent occupés.. même une heure après.. et je comprends pas.

Bon, t'as toujours raison j'imagine ...
 

Bool

WRInaute passionné
Effectivement j'ai lu un peu vite, désolé. Disons que cette formulation :
Si tu utilises plus les 1.8go de la ram et que le systeme a besoin de mémoire libre, ne t'inquiète pas, il va les virer si ca fait des heures que c'est plus utilisé
Pour moi laisse penser que la notion de "temps" intervient, ce qui est en partie faux. Même si les données viennent d'être utilisées 5ms avant, elles seront dégagées si besoin.

Mais on va dire que tu as oublié le terme "surtout" dans ta phrase.
 

YoyoS

WRInaute accro
Moi tout ce que je voulais dire, sans trop m'avancer au niveau technique, c'est qu'il classe les infos dans la mémoire par ordre de fréquence d'utilisation afin de trouver lesquelles supprimer.

T'es sure que le temps ne joue pas ? Même s'il s'agit de nanosecondes ? :D Parce que 5ns ou 1h c'est du temps quand même :D Et faut bien qu'il se base sur la date du dernier temps d'accès à l'information pour savoir laquelle supprimer ?
 

Bool

WRInaute passionné
Oui, il s'en sert pour "prioriser" les données et va commencer par dégager ce qui sert le moins. Mais il n'y a pas de "limite minimum" : si le cache fait 300Mo et qu'il a besoin de 300Mo il va dégager tout le cache, même pour 5ms.
 

Discussions similaires

Haut