IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Memory Leak avec la fonction exec() [PHP 5.4]


Sujet :

Langage PHP

  1. #1
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut Memory Leak avec la fonction exec()
    Bonjour à tous et toutes,

    Je vous sollicite car je rencontre actuellement un problème dans l'un de mes scripts PHP (appel en crontab).

    Ce dernier a pour rôle d'effectuer une requête en base de données et de générer un fichier CSV brut.
    La requête est colossale : extraction de tout un référentiel avec un croisement d'une table de 3Go avec une multitude d'autres tables.
    La requête est brute : pas de filtre, pas de tri, un simple SELECT X FROM X JOIN X [...]
    L'écriture du fichier est brut : le résultat de la requête tel qu'obtenu.

    Il n'y a donc aucun traitement PHP nécessaire. Afin de ne pas avoir à parcourir les 8 millions de lignes retournées pour l'écriture dans le fichier, j'ai opté pour la solution basique suivante :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $commande = "mysql -u $login -p$password -h $host $db -e \"$query\" | sed 's/NULL//g;s/\t/;/g;s/$/;/;s/\\n//g' > $path/$file";
    exec($commande);
    Le sed permet juste d'afficher l'entête dans le fichier.

    Le traitement est donc demandé au système via la commande exec().

    Pourtant, j'obtiens l'erreur suivante :

    PHP Fatal error: Allowed memory size of 838860800 bytes exhausted (tried to allocate 72 bytes) in [...]
    sachant que ma mémoire est en effet configurée à 800Mo :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ini_set('memory_limit', '800M');
    Ce que je ne comprends pas, c'est pourquoi la mémoire PHP est-elle sollicitée dans ce contexte, d'autant plus que je ne demande pas à exec() de stocker le flux de sortie ou de résultat de la commande.

    Auriez-vous une explication ?

    Merci pour votre aide.

  2. #2
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Points : 44 155
    Points
    44 155
    Par défaut
    La ligne indiquée dans l'erreur n'a besoin que de 72 octets.
    Les 799,999Mo sont utilisées avant.

  3. #3
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Merci pour ta rapide réponse sabotage.

    Je n'ai en revanche aucun traitement en amont de l'exécution de la commande exec() (à par la construction de la requête mais ce n'est que la création d'une variable de chaîne de caractères) et le script ne franchi jamais cette étape (qui plante au bout d'1h15 à peu près).

    J'ai tenté de monter la mémoire à 1Go (aucun autre changement niveau code)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ini_set('memory_limit', '1000M');
    L'erreur devient alors la suivante :

    PHP Fatal error: Allowed memory size of 1048576000 bytes exhausted (tried to allocate 72 bytes)

  4. #4
    Membre expert
    Avatar de Spartacusply
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mai 2011
    Messages
    1 723
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2011
    Messages : 1 723
    Points : 3 275
    Points
    3 275
    Par défaut
    En interne je pense php doit stocker le résultat de chaque ligne de sortie de cette commande (même s'il ne retourne que la dernière).

    Essaye ce qui est indiqué dans la doc (sans garantie de résultat) :

    Note:
    Si vous démarrez un programme en utilisant cette fonction et que vous voulez le laisser tourner en arrière plan, vous devez vous assurer que la sortie du programme est redirigée vers un fichier, ou un autre flux de sortie, sinon PHP attendra jusqu'à la fin de l'exécution du programme.
    EDIT : mieux, lance ta commande en mode silencieux (aucun retour dans la console), option '-s'

  5. #5
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Merci pour ta réponse Spartacusply,

    La sortie du programme est déjà redirigée vers un fichier. Voici la CRON qui est chargée de l'exécution :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    30 3 * * * cd ... ; php cli.php --env=production --action=extractReferentiel >> /tmp/cronExtractReferentiel.log 2>&1
    Je vais tenter l'option -s pour la commande mysql, je vous tiens au courant du comportement.

  6. #6
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Après 1h30 d'exécution, avec l'option -s de mysql, le comportement est toujours le même

    PHP Fatal error: Allowed memory size of 1258291200 bytes exhausted (tried to allocate 119 bytes)
    (j'avais monté la mémoire à 1.2Go).

    Je ne comprends vraiment pas pourquoi la mémoire PHP est sollicitée...

  7. #7
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Points : 44 155
    Points
    44 155
    Par défaut
    Est-ce que tu as le même comportement avec system() ?

  8. #8
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Points : 2 440
    Points
    2 440
    Par défaut
    3 Go c'est lourd :-(

    Tu ne peux pas créer ton csv directement depuis MySql, sans passer par PHP?

    http://www.tech-recipes.com/rx/1475/...t-or-csv-file/

  9. #9
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Hello à tous et merci pour vos réponses.

    @sabotage
    Le passage à l'instruction system() ne résout pas le problème. En revanche, j'ai baissé volontairement la mémoire à 400Mo pour éviter d'attendre trop longtemps et je constate que ca a planté également au bout d'1h30
    Je me demande s'il n'y a pas un autre problème qui se cache derrière tout cela., ça me semble étrange que ça n'ait pas planté plus rapidement.

    @Tsilefy
    En effet les données traitées sont conséquentes.
    J'envisageais en effet d'abandonner PHP et de directement exécuter l'instruction SQL par un script shell des plus basique.
    J'essaye toutefois de comprendre pourquoi la mémoire PHP est sollicitée dans ce contexte précis, d'autant plus que ce script tournait très bien il y a quelques semaines (avant la reconfiguration des serveurs par les DBA.)

    A défaut de mieux, je basculerai donc sur du scripting shell pour ces quelques actions., mais pour l'instant, je persévère et essaie de comprendre !

  10. #10
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Bonjour à tous !

    Je viens vous donner quelques nouvelles concernant ce problème.
    J'ai finalement opté pour du scripting shell : un script sh s'occupe d'effectuer les requêtes en base de données et le script PHP reprend ensuite la main pour effectuer les vérifications qui vont bien puis le transfert SFTP.
    Le problème est ainsi résolu de cette manière.

    J'en profite également pour préciser, et cela faisait certainement parti d'une des causes de ce comportement, qu'effectuer l'instruction

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $nb = count(file($filepath_vers_mon_fichier));
    pour compter le nombre de ligne d'un fichier n'est pas une très bonne idée, toutes les données étant stockées en mémoire.

    Donc au final grosses requêtes + count d'un gros fichier en mémoire = problème.

    J'ai opté pour l'instruction

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    exec("wc - l $filepath_vers_mon_fichier | awk '{ $2 = \"\"; print }'", $count);
    pour effectuer le comptage.


    En tout cas merci à tous pour votre aide et à très bientôt sur Developpez !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Système] Pb avec la fonction exec
    Par MayOL69bg dans le forum Langage
    Réponses: 9
    Dernier message: 24/05/2007, 19h12
  2. [Système] P'tit soucis avec la fonction EXEC
    Par nais_ dans le forum Langage
    Réponses: 9
    Dernier message: 23/08/2006, 11h36
  3. [Système] Probleme de PATH avec la fonction exec
    Par Sylvain71 dans le forum Langage
    Réponses: 11
    Dernier message: 16/07/2006, 17h04
  4. [Système] problème avec la fonction exec
    Par SegmentationFault dans le forum Langage
    Réponses: 1
    Dernier message: 30/06/2006, 17h59
  5. [Système] Problème avec la fonction exec()
    Par ben_harper dans le forum Langage
    Réponses: 13
    Dernier message: 28/06/2006, 11h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo