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

Multithreading Discussion :

Explosion de la consommation mémoire


Sujet :

Multithreading

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 42
    Par défaut Explosion de la consommation mémoire
    Bonjour,

    J'ai un soucis avec QThread. Voilà le soucis:

    Je suis en train d'écrire une système de log avec architecture : un LogManager qui contient les fonctions de log ( trace, warning , ... ) et une collection d'"engine" qui eux s'occupe d'écrire les logs proprement dit.

    Les engines tourne dans un thread, chacun le leur et la communication entre le LogManager et les engines se fait via les signaux/slots.

    Cependant j'ai un soucis, la mémoire vive utilisé par l'application explose et très rapidement ( avec une boucle infinie avec un trace("TEST") et 4 engines => 15 secondes = 1Go5 de mémoire prise ). J'ai donc pensé a une leak, sauf que il n'y a pas d'allocation dynamique dans le code.
    Ci dessus des extraits de code:

    La méthode pour ajouter un engine:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void LogManager::addLoggerEngine(QString engineName, LoggerEngine* engine)
    {	
    	m_loggerEngines.insert(engineName, engine);	
    	engine->moveToThread(thread); /* Work but cause a memory leak, had to fix that */
    	connect(this, SIGNAL(logMessage(LogManager::LogLevel, QList<QVariant>)), engine, SLOT(writeFormatted(LogManager::LogLevel, QList<QVariant>)));	
    	thread->start(); /* line that cause leak concern QDateTime::currentDate().ToString("format") */
     
    	emit loggerEngineAdded(engineName);
    }
    La méthode pour loguer:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void LogManager::log ( LogLevel level, const QList<QVariant> & args )
    {	
    	emit logMessage(level, args);
    }
    Prototype du signal:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void logMessage(LogManager::LogLevel level, QList<QVariant> args);
    Un des slots: ( tous on le même soucis )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    void ConsoleLoggerEngine::writeFormatted(LogManager::LogLevel level, QList<QVariant> messages )
    {
     
    	if(!m_isEnabled) return;
    	if (messages.isEmpty()) return;
    	if(!isLogLevelEnabled(level)) return;
     
    	QString header = '[' + QTime::currentTime().toString("hh:mm:ss.zzz") + "] [" + LogManager::logLevelToString(level) + "] ";
        QString padding;
     
        *stdstream << header;
        padding.append(' ');
        int count = 0;
     
        Q_FOREACH(const QVariant& out, messages)
        {
            if (!out.isNull())
            {
                if (count != 0) *stdstream << padding;
                *stdstream << out.toString();
            }
            count++;
        }
        *stdstream << endl;
    }
    En sachant que si je commente ce code = plus de soucis

    Cordialement Mathieu

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Salut.
    C'est quoi stdstream ?

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 42
    Par défaut
    Bonjour
    stdstream est un QTextStream binder sur la sortie console.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ConsoleLoggerEngine::ConsoleLoggerEngine(QObject *parent) : LoggerEngine(parent)
    {	
    	stdstream = new QTextStream(stdout);
    }
     
    ConsoleLoggerEngine::~ConsoleLoggerEngine()
    {
    	delete stdstream;
    }

  4. #4
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Comment voie tu la mémoire utilisé?
    Es ce que ton appli crash a cause d'un manque de mémoire?

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 42
    Par défaut
    J'utilise le gestionnaire de tache. Je sais bien que ce n'est pas forcément très précis mais je vois la mémoire vive monté très rapidement donc pas on signe ^^.

    Si j'attend , l'application ne plante pas , elle ralenti mais je suis cappé en RAM utilisé ( 8Go dont 6Go5 par l'application si j'en crois le gestionnaire des taches )

  6. #6
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par lange59 Voir le message
    J'utilise le gestionnaire de tache. Je sais bien que ce n'est pas forcément très précis mais je vois la mémoire vive monté très rapidement donc pas on signe ^^.
    ^^

    Bizarre. Car dans le code que tu donne, il n'y as rien de spéciale.
    Tu es sur que c'est lié à ton slot?
    N'aurais tu pas une sorte à ton slot de manière récursive?
    Que contient QList<QVariant>?

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 42
    Par défaut
    Up.

    Le problème est toujours là. Je commence a croire qu'il y a un soucis de libération de ressources avec le système de Signals/Slots quand on l'utilise pour la connection inter-thread.
    J'ai continué à faire des tests et le problème se repete sans cesse.

    Si quelqu'un a une réponse je suis preneur

    Cordialement lange

  8. #8
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    as tu essayé d'avoir a.exec ?

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 42
    Par défaut
    Purée ca me rend fou.

    C'était bien ça. J'ai modifier le code et utliser des QTimer pour envoyer les signaux à mes threads et ajouter un a.exec() comme retour du main et là plus de soucis.
    C'est quand même étrange , on dirait que Qt garde en stocks les paramétres de slots et ne les "nettoie" que si une boucle d'evenement est lancé dans le thread principal.
    Le problème c'est que ca n'est indiqué nul part dans la doc de Qt (et je l'ai fouillé de fond en comble ).

    Merci pour le coup de main. Je vais enfin avoir mon système de logs multithreaded .

    EDIT: C'est pas ça le problème, j'ai trouvé d'ou ca vient .

    Je viens a l'instant de m'en rendre compte, si je diminue au mininium la vitesse de tick du QTimer (donc timer.start(): la mémoire utilisé augmente comme pendant le "bug", quand je l'a met a un "niveau raisonnable" ( timer.start(1) ) = plus de soucis.
    C'est donc pas un bug, c est le système d'evenement de Qt qui n'arrive pas gérer aussi vite les evenements donc il les met en queue, d'ou une copie des parametres d'ou une augmentation de la mémoire .

    Exemple de Code:

    La classe Thread est juste une sous classe de QThread qui sert de relais pour les signaux entre le thread principal et une sous classe QObject vivant dans le thread et qui ne fait rien de spécial ( log l'id du thread courant )

    Code qui "leak":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    	Thread thread1;
    	Thread thread2;
    	Thread thread3;
    	Thread thread4;
     
    	thread1.start();
    	thread2.start();
    	thread3.start();
    	thread4.start();
     
    	forever
    	{
    		thread1.TestFonction();
    		thread2.TestFonction();
    		thread3.TestFonction();
    		thread4.TestFonction();
    	}
          return a.exec();
    // return 0; Les deux leak


    Cette version "leak" aussi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    	Thread thread1;
    	Thread thread2;
    	Thread thread3;
    	Thread thread4;
     
    	thread1.start();
    	thread2.start();
    	thread3.start();
    	thread4.start();
     
    	QTimer timer1;
    	QObject::connect(&timer1, SIGNAL(timeout()), &thread1, SLOT(TestFonction()));
    	QObject::connect(&timer1, SIGNAL(timeout()), &thread2, SLOT(TestFonction()));
    	QObject::connect(&timer1, SIGNAL(timeout()), &thread3, SLOT(TestFonction()));
    	QObject::connect(&timer1, SIGNAL(timeout()), &thread4, SLOT(TestFonction()));
        timer1.start();
     
    return a.exec();
    Ces deux versions ne leak pas:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    	Thread thread1;
    	Thread thread2;
    	Thread thread3;
    	Thread thread4;
     
    	thread1.start();
    	thread2.start();
    	thread3.start();
    	thread4.start();
     
    	QTimer timer1;
    	QObject::connect(&timer1, SIGNAL(timeout()), &thread1, SLOT(TestFonction()));
    	QObject::connect(&timer1, SIGNAL(timeout()), &thread2, SLOT(TestFonction()));
    	QObject::connect(&timer1, SIGNAL(timeout()), &thread3, SLOT(TestFonction()));
    	QObject::connect(&timer1, SIGNAL(timeout()), &thread4, SLOT(TestFonction()));
        timer1.start(1);
     
     
    	return a.exec();
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Thread thread1;
    	Thread thread2;
    	Thread thread3;
    	Thread thread4;
     
    	thread1.start();
    	thread2.start();
    	thread3.start();
    	thread4.start();
     
    	forever
    	{
    		thread1.TestFonction();
    		thread2.TestFonction();
    		thread3.TestFonction();
    		thread4.TestFonction();
                    Sleep(1);
    	}
          return a.exec();
    Cordialement Mathieu

  10. #10
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    lors d'une connection entre thread, un évènement est ajouté à l'eventloop du thread pour executer le slot. Donc si tu en envoie trop tu fais exploser l'eventloop ^^

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

Discussions similaires

  1. Voir la consommation mémoire
    Par MicroPuce dans le forum Général Java
    Réponses: 4
    Dernier message: 10/10/2006, 09h19
  2. [C#] probleme de consommation mémoire
    Par xtream dans le forum Windows Forms
    Réponses: 3
    Dernier message: 21/06/2006, 13h16
  3. [TStringGrid] Consommation mémoire
    Par spender dans le forum Bases de données
    Réponses: 4
    Dernier message: 09/03/2006, 21h48
  4. [Consommation mémoire] Quoi utiliser pour trouver?
    Par doudine dans le forum Interfaces Graphiques en Java
    Réponses: 1
    Dernier message: 25/01/2006, 13h50
  5. Réponses: 4
    Dernier message: 09/11/2005, 13h32

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